03、工厂模式.md

工厂模式

目录

  • 工厂模式
    • 图解
  • 简单工厂
    • 代码编写
    • 单元测试
  • 工厂方法
    • 代码编写
    • 单元测试
  • 抽象工厂
    • 代码编写
    • 单元测试
  • DI 容器
    • 代码实现
    • example

图解

*

简单工厂

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

代码编写

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
}

单元测试

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 一下就可以,而是要组合其他类对象,做各种初始化操作的时候,推荐使用工厂方法模式,将复杂的创建逻辑拆分到多个工厂类中,让每个工厂类都不至于过于复杂

代码编写

// 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
}

单元测试

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)
			}
		})
	}
}

抽象工厂

代码编写

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{
   
     }
}

单元测试

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 现有的依赖注入框架:

  • 使用反射实现的: https://github.com/uber-go/dig
  • 使用 generate 实现的: https://github.com/google/wire

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

代码实现

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

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)
	}
}

版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: