Go设计模式02-工厂模式&DI容器

注:本文已发布超过一年,请注意您所使用工具的相关版本是否适用

代码实现

简单工厂

由于 Go 本身是没有构造函数的,一般而言我们采用 NewName  的方式创建对象/接口,当它返回的是接口的时候,其实就是简单工厂模式

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
package factory

// IRuleConfigParser IRuleConfigParser
type IRuleConfigParser interface {
Parse(data []byte)
}

// jsonRuleConfigParser jsonRuleConfigParser
type jsonRuleConfigParser struct {
}

// Parse Parse
func (J jsonRuleConfigParser) Parse(data []byte) {
panic("implement me")
}

// yamlRuleConfigParser yamlRuleConfigParser
type yamlRuleConfigParser struct {
}

// Parse Parse
func (Y yamlRuleConfigParser) Parse(data []byte) {
panic("implement me")
}

// NewIRuleConfigParser NewIRuleConfigParser
func NewIRuleConfigParser(t string) IRuleConfigParser {
switch t {
case "json":
return jsonRuleConfigParser{}
case "yaml":
return yamlRuleConfigParser{}
}
return nil
}

单元测试

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
package factory

import (
"reflect"
"testing"
)

func TestNewIRuleConfigParser(t *testing.T) {
type args struct {
t string
}
tests := []struct {
name string
args args
want IRuleConfigParser
}{
{
name: "json",
args: args{t: "json"},
want: jsonRuleConfigParser{},
},
{
name: "yaml",
args: args{t: "yaml"},
want: yamlRuleConfigParser{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := NewIRuleConfigParser(tt.args.t); !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewIRuleConfigParser() = %v, want %v", got, tt.want)
}
})
}
}

工厂方法

当对象的创建逻辑比较复杂,不只是简单的 new 一下就可以,而是要组合其他类对象,做各种初始化操作的时候,推荐使用工厂方法模式,将复杂的创建逻辑拆分到多个工厂类中,让每个工厂类都不至于过于复杂

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
// IRuleConfigParserFactory 工厂方法接口
type IRuleConfigParserFactory interface {
CreateParser() IRuleConfigParser
}

// yamlRuleConfigParserFactory yamlRuleConfigParser 的工厂类
type yamlRuleConfigParserFactory struct {
}

// CreateParser CreateParser
func (y yamlRuleConfigParserFactory) CreateParser() IRuleConfigParser {
return yamlRuleConfigParser{}
}

// jsonRuleConfigParserFactory jsonRuleConfigParser 的工厂类
type jsonRuleConfigParserFactory struct {
}

// CreateParser CreateParser
func (j jsonRuleConfigParserFactory) CreateParser() IRuleConfigParser {
return jsonRuleConfigParser{}
}

// NewIRuleConfigParserFactory 用一个简单工厂封装工厂方法
func NewIRuleConfigParserFactory(t string) IRuleConfigParserFactory {
switch t {
case "json":
return jsonRuleConfigParserFactory{}
case "yaml":
return yamlRuleConfigParserFactory{}
}
return nil
}

单元测试

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
package factory

import (
"reflect"
"testing"
)

func TestNewIRuleConfigParserFactory(t *testing.T) {
type args struct {
t string
}
tests := []struct {
name string
args args
want IRuleConfigParserFactory
}{
{
name: "json",
args: args{t: "json"},
want: jsonRuleConfigParserFactory{},
},
{
name: "yaml",
args: args{t: "yaml"},
want: yamlRuleConfigParserFactory{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := NewIRuleConfigParserFactory(tt.args.t); !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewIRuleConfigParserFactory() = %v, want %v", got, tt.want)
}
})
}
}

抽象工厂

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
package factory

// IRuleConfigParser IRuleConfigParser
type IRuleConfigParser interface {
Parse(data []byte)
}

// jsonRuleConfigParser jsonRuleConfigParser
type jsonRuleConfigParser struct{}

// Parse Parse
func (j jsonRuleConfigParser) Parse(data []byte) {
panic("implement me")
}

// ISystemConfigParser ISystemConfigParser
type ISystemConfigParser interface {
ParseSystem(data []byte)
}

// jsonSystemConfigParser jsonSystemConfigParser
type jsonSystemConfigParser struct{}

// Parse Parse
func (j jsonSystemConfigParser) ParseSystem(data []byte) {
panic("implement me")
}

// IConfigParserFactory 工厂方法接口
type IConfigParserFactory interface {
CreateRuleParser() IRuleConfigParser
CreateSystemParser() ISystemConfigParser
}

type jsonConfigParserFactory struct{}

func (j jsonConfigParserFactory) CreateRuleParser() IRuleConfigParser {
return jsonRuleConfigParser{}
}

func (j jsonConfigParserFactory) CreateSystemParser() ISystemConfigParser {
return jsonSystemConfigParser{}
}

单元测试

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
package factory

import (
"reflect"
"testing"
)

func Test_jsonConfigParserFactory_CreateRuleParser(t *testing.T) {
tests := []struct {
name string
want IRuleConfigParser
}{
{
name: "json",
want: jsonRuleConfigParser{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
j := jsonConfigParserFactory{}
if got := j.CreateRuleParser(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("CreateRuleParser() = %v, want %v", got, tt.want)
}
})
}
}

func Test_jsonConfigParserFactory_CreateSystemParser(t *testing.T) {
tests := []struct {
name string
want ISystemConfigParser
}{
{
name: "json",
want: jsonSystemConfigParser{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
j := jsonConfigParserFactory{}
if got := j.CreateSystemParser(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("CreateSystemParser() = %v, want %v", got, tt.want)
}
})
}
}

DI 容器

golang 现有的依赖注入框架:

下文将通过反射实现一个类似 dig 简单的 demo,在课程里面的例子是读取配置文件,然后进行生成,下面提供是通过 provider 进行构建依赖关系。

代码实现

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package di

import (
"fmt"
"reflect"
)

// Container DI 容器
type Container struct {
// 假设一种类型只能有一个 provider 提供
providers map[reflect.Type]provider

// 缓存以生成的对象
results map[reflect.Type]reflect.Value
}

type provider struct {
value reflect.Value

params []reflect.Type
}

// New 创建一个容器
func New() *Container {
return &Container{
providers: map[reflect.Type]provider{},
results: map[reflect.Type]reflect.Value{},
}
}

// isError 判断是否是 error 类型
func isError(t reflect.Type) bool {
if t.Kind() != reflect.Interface {
return false
}
return t.Implements(reflect.TypeOf(reflect.TypeOf((*error)(nil)).Elem()))
}

// Provide 对象提供者,需要传入一个对象的工厂方法,后续会用于对象的创建
func (c *Container) Provide(constructor interface{}) error {
v := reflect.ValueOf(constructor)

// 仅支持函数 provider
if v.Kind() != reflect.Func {
return fmt.Errorf("constructor must be a func")
}

vt := v.Type()

// 获取参数
params := make([]reflect.Type, vt.NumIn())
for i := 0; i < vt.NumIn(); i++ {
params[i] = vt.In(i)
}

// 获取返回值
results := make([]reflect.Type, vt.NumOut())
for i := 0; i < vt.NumOut(); i++ {
results[i] = vt.Out(i)
}

provider := provider{
value: v,
params: params,
}

// 保存不同类型的 provider
for _, result := range results {
// 判断返回值是不是 error
if isError(result) {
continue
}

if _, ok := c.providers[result]; ok {
return fmt.Errorf("%s had a provider", result)
}

c.providers[result] = provider
}

return nil
}

// Invoke 函数执行入口
func (c *Container) Invoke(function interface{}) error {
v := reflect.ValueOf(function)

// 仅支持函数 provider
if v.Kind() != reflect.Func {
return fmt.Errorf("constructor must be a func")
}

vt := v.Type()

// 获取参数
var err error
params := make([]reflect.Value, vt.NumIn())
for i := 0; i < vt.NumIn(); i++ {
params[i], err = c.buildParam(vt.In(i))
if err != nil {
return err
}
}

v.Call(params)

// 获取 providers
return nil
}

// buildParam 构建参数
// 1. 从容器中获取 provider
// 2. 递归获取 provider 的参数值
// 3. 获取到参数之后执行函数
// 4. 将结果缓存并且返回结果
func (c *Container) buildParam(param reflect.Type) (val reflect.Value, err error) {
if result, ok := c.results[param]; ok {
return result, nil
}

provider, ok := c.providers[param]
if !ok {
return reflect.Value{}, fmt.Errorf("can not found provider: %s", param)
}

params := make([]reflect.Value, len(provider.params))
for i, p := range provider.params {
params[i], err = c.buildParam(p)
}

results := provider.value.Call(params)
for _, result := range results {
// 判断是否报错
if isError(result.Type()) && !result.IsNil() {
return reflect.Value{}, fmt.Errorf("%s call err: %+v", provider, result)
}

if !isError(result.Type()) && !result.IsNil() {
c.results[result.Type()] = result
}
}
return c.results[param], nil
}

我们这里的实现比较粗糙,但是作为一个 demo 理解 di 容器也足够了,和 dig 相比还缺少很多东西,并且有许多的问题,例如 依赖关系,一种类型如果有多个 provider 如何处理等等等等。
可以看到我们总共就三个函数

  • Provide: 获取对象工厂,并且使用一个 map 将对象工厂保存
  • Invoke: 执行入口
  • buildParam: 核心逻辑,构建参数
    • 从容器中获取 provider
    • 递归获取 provider 的参数值
    • 获取到参数之后执行函数
    • 将结果缓存并且返回结果

example

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
52
53
54
55
56
57
58
59
60
61
package main

import (
"fmt"

di "github.com/mohuishou/go-design-pattern/02_factory/024_di"
)

// A 依赖关系 A -> B -> C
type A struct {
B *B
}

// NewA NewA
func NewA(b *B) *A {
return &A{
B: b,
}
}

// B B
type B struct {
C *C
}

// NewB NewB
func NewB(c *C) *B {
return &B{C: c}
}

// C C
type C struct {
Num int
}

// NewC NewC
func NewC() *C {
return &C{
Num: 1,
}
}

func main() {
container := di.New()
if err := container.Provide(NewA); err != nil {
panic(err)
}
if err := container.Provide(NewB); err != nil {
panic(err)
}
if err := container.Provide(NewC); err != nil {
panic(err)
}

err := container.Invoke(func(a *A) {
fmt.Printf("%+v: %d", a, a.B.C.Num)
})
if err != nil {
panic(err)
}
}

关注我获取更新

wechat
知乎
github

猜你喜欢