Go模板模式14-模板模式

笔记

代码实现

举个 🌰,假设我现在要做一个短信推送的系统,那么需要

  1. 检查短信字数是否超过限制
  2. 检查手机号是否正确
  3. 发送短信
  4. 返回状态

我们可以发现,在发送短信的时候由于不同的供应商调用的接口不同,所以会有一些实现上的差异,但是他的算法(业务逻辑)是固定的

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package template

import "fmt"

// ISMS ISMS
type ISMS interface {
send(content string, phone int) error
}

// SMS 短信发送基类
type sms struct {
ISMS
}

// Valid 校验短信字数
func (s *sms) Valid(content string) error {
if len(content) > 63 {
return fmt.Errorf("content is too long")
}
return nil
}

// Send 发送短信
func (s *sms) Send(content string, phone int) error {
if err := s.Valid(content); err != nil {
return err
}

// 调用子类的方法发送短信
return s.send(content, phone)
}

// TelecomSms 走电信通道
type TelecomSms struct {
*sms
}

// NewTelecomSms NewTelecomSms
func NewTelecomSms() *TelecomSms {
tel := &TelecomSms{}
// 这里有点绕,是因为 go 没有继承,用嵌套结构体的方法进行模拟
// 这里将子类作为接口嵌入父类,就可以让父类的模板方法 Send 调用到子类的函数
// 实际使用中,我们并不会这么写,都是采用组合+接口的方式完成类似的功能
tel.sms = &sms{ISMS: tel}
return tel
}

func (tel *TelecomSms) send(content string, phone int) error {
fmt.Println("send by telecom success")
return nil
}

单元测试

1
2
3
4
5
6
7
8
9
10
11
12
13
package template

import (
"testing"

"github.com/stretchr/testify/assert"
)

func Test_sms_Send(t *testing.T) {
tel := NewTelecomSms()
err := tel.Send("test", 1239999)
assert.NoError(t, err)
}