【设计模式】2、工厂:简单工厂、工厂方法、抽象工厂

时间:2024-04-14 07:41:07

文章目录

  • 二、工厂
    • 2.1 简单工厂
    • 2.2 工厂方法
      • 2.2.1 目录层级
      • 2.2.2 使用方式
      • 2.2.3 产品、简单工厂的定义
      • 2.2.4 具体工厂的定义
      • 2.2.5 具体工厂的实现
    • 2.3 抽象工厂
      • 2.3.1 目录层级
      • 2.3.2 使用工厂
      • 2.3.3 定义工厂
      • 2.3.4 定义产品
      • 2.3.5 json config 的实现
      • 2.3.6 yaml config 的具体实现:工厂和产品

二、工厂

https://github.com/ssbandjl/golang-design-pattern/tree/master/00_simple_factory

https://github.com/*ishou/go-design-pattern/blob/master/02_factory/021_simple_factory/simple_factory.go

分为:简单工厂、工厂方法、抽象工厂。

2.1 简单工厂

因为 go 本身没有构造函数, 通常用 NewXXX 构造, 当返回接口时, 就是简单工厂

可以按如下平铺的目录层级,也可以用分层的目录层级:

02factory/021simple_factory
├── json_parser
│   └── json_parser.go
├── simple_factory.go
├── simple_factory_test.go
└── yaml_parser
    └── yaml_parser.go

simple_factory.go 描述了工厂如下:

package simplefactory

import (
    "godp/02factory/021simple_factory/json_parser"
    "godp/02factory/021simple_factory/yaml_parser"
)

// ConfigParser 是产品的接口
type ConfigParser interface {
    Parse(b []byte) error
}

// NewConfigParser 是工厂
// 当构造函数返回接口时就是工厂
// 当在一个工厂, 生产多种产品时, 就是简单工厂
func NewConfigParser(typ string) ConfigParser {
    switch typ {
    case "json":
       return &json_parser.ConfigParser{}
    case "yaml":
       return &yaml_parser.ConfigParser{}
    }
    return nil
}

工厂的测试如下:

package simplefactory

import (
    "github.com/stretchr/testify/require"
    "godp/02factory/021simple_factory/json_parser"
    "godp/02factory/021simple_factory/yaml_parser"
    "testing"
)

func TestNewConfigParser(t *testing.T) {
    j := NewConfigParser("json")
    require.Equal(t, j, &json_parser.ConfigParser{})

    y := NewConfigParser("yaml")
    require.Equal(t, y, &yaml_parser.ConfigParser{})
}

json 产品的实现如下:

package json_parser

import "encoding/json"

// ConfigParser 是 json 产品的具体实现
type ConfigParser struct{}

func (p *ConfigParser) Parse(b []byte) error {
    v := struct{}{}
    return json.Unmarshal(b, &v)
}

yaml 产品的实现如下:

package yaml_parser

import "gopkg.in/yaml.v3"

// ConfigParser 是 yaml 产品的具体实现
type ConfigParser struct{}

func (p *ConfigParser) Parse(b []byte) error {
    v := struct{}{}
    return yaml.Unmarshal(b, &v)
}

2.2 工厂方法

如果需要每种产品生产的过程比较复杂,不适合放在一个简单工厂中。

则可以把每种产品,都封装一个工厂。

在简单工厂中,根据传入的类型,构造不同的工厂。

这种模式,就是工厂方法模式,也是实践中最常用的。

2.2.1 目录层级

目录层级如下:

02factory/022factory_method
├── factory.go
├── factory_test.go
├── json_factory.go
├── json_parser
│   └── json_parser.go
├── yaml_factory.go
└── yaml_parser
    └── yaml_parser.go

2.2.2 使用方式

从 factory_test.go 的单测,可以看出使用方式:

package factory_method

import (
    "github.com/stretchr/testify/require"
    "godp/02factory/022factory_method/json_parser"
    "godp/02factory/022factory_method/yaml_parser"
    "testing"
)

// 链式
func TestCreateJsonParserByChain(t *testing.T) {
    err := CreateConfigParserFactory(jsonFactoryType).Create().Parse([]byte("{}"))
    require.NoError(t, err)
}

func TestCreateYamlParserByChain(t *testing.T) {
    err := CreateConfigParserFactory(yamlFactoryType).Create().Parse([]byte("{}"))
    require.NoError(t, err)
}

// 详细步骤分解
func TestCreateJsonConfigParser(t *testing.T) {
    jsonFactory := CreateConfigParserFactory(jsonFactoryType)
    require.Equal(t, jsonFactory, new(jsonConfigParserFactory))

    jsonParser := jsonFactory.Create()
    require.Equal(t, jsonParser, new(json_parser.JsonConfigParser))

    err := jsonParser.Parse([]byte("{}"))
    require.NoError(t, err)
}

func TestYamlConfigParser(t *testing.T) {
    f := CreateConfigParserFactory(yamlFactoryType)
    require.Equal(t, f, new(yamlConfigParserFactory))

    parser := f.Create()
    require.Equal(t, parser, new(yaml_parser.YamlConfigParser))

    err := parser.Parse([]byte("{}"))
    require.NoError(t, err)
}

2.2.3 产品、简单工厂的定义

factory.go 定义了产品、工厂:

package factory_method

// ConfigParser 是生产出的产品的接口
type ConfigParser interface {
    Parse(b []byte) error
}

// ConfigParserFactory 是工厂的接口, 其可以生产产品
type ConfigParserFactory interface {
    Create() ConfigParser
}

// FactoryType 是 工厂的类型
type FactoryType string

// CreateConfigParserFactory 是向 package 外暴露的方法
// 其用一个简单工厂, 封装工厂方法, 根据数据的工厂类型, 生成对应的工厂(后续可使用对应的工厂, 生产对应的产品)
func CreateConfigParserFactory(typ FactoryType) ConfigParserFactory {
    switch typ {
    case jsonFactoryType:
       return new(jsonConfigParserFactory)
    case yamlFactoryType:
       return new(yamlConfigParserFactory)
    }
    return nil
}

2.2.4 具体工厂的定义

工厂方法,会根据 type 返回具体的工厂

Json_factory.go 如下:

package factory_method

import "godp/02factory/022factory_method/json_parser"

const jsonFactoryType FactoryType = "json"

// jsonConfigParserFactory 是 Json 的工厂
type jsonConfigParserFactory struct {
}

func (f *jsonConfigParserFactory) Create() ConfigParser {
	return new(json_parser.JsonConfigParser)
}

yaml_factory.go 如下:

package factory_method

import "godp/02factory/022factory_method/yaml_parser"

const yamlFactoryType FactoryType = "yaml"

// yamlConfigParserFactory 是生产 yamlConfigParser 的工厂
type yamlConfigParserFactory struct {
}

func (f *yamlConfigParserFactory) Create() ConfigParser {
	return new(yaml_parser.YamlConfigParser)
}

2.2.5 具体工厂的实现

每个具体实现,都可以创建一个单独的 子 package。即【父 package】定义了产品和简单工厂,【子 package】实现各具体工厂的创建逻辑。

json_parser/json_parser.go 如下:

package json_parser

import "encoding/json"

type JsonConfigParser struct{}

func (j *JsonConfigParser) Parse(b []byte) error {
    v := struct{}{}
    return json.Unmarshal(b, &v)
}

yaml_parser/yaml_parser.go 如下:

package yaml_parser

import "gopkg.in/yaml.v3"

type YamlConfigParser struct {
}

func (y *YamlConfigParser) Parse(b []byte) error {
    v := struct{}{}
    return yaml.Unmarshal(b, &v)
}

2.3 抽象工厂

之前的【工厂方法】都是指生产一种产品,如果生产多种产品就是抽象工厂。参考:https://refactoringguru.cn/design-patterns/abstract-factory

因为【工厂方法】每增加一种产品,就需要增加一个工厂,这样工厂太多了。所以可以把产品分组,使一个工厂生产多种产品,这就是【抽象工厂】。

例如,如果客户端希望生产服装产品(鞋子、衣服),他们又分为不同厂商的。具体如下:

  • Adidas 鞋子
  • Adidas 衣服
  • Nike 鞋子
  • Nike 衣服

则,可以用 Adidas 工厂,生产 Adidas 鞋子和 Adidas 衣服。

再用 Nike 工厂,生产 Nike 鞋子和 Nike 衣服。

因为每种工厂,生产了多件产品(如鞋子、衣服),所以这种模式就是抽象工厂。

2.3.1 目录层级

02factory/023abstract_factory
├── factory.go
├── factory_test.go
├── json_config
│   ├── factory.go
│   ├── generator.go
│   ├── parser.go
│   └── readme.md
├── model
│   ├── generator.go
│   ├── parser.go
│   ├── readme.md
│   └── type.go
└── yaml_config
    ├── factory.go
    ├── generator.go
    ├── parser.go
    └── readme.md

2.3.2 使用工厂

factory_test.go

package abstract_factory

import (
	"github.com/stretchr/testify/require"
	"godp/02factory/023abstract_factory/model"
	"testing"
)

func TestCreateJsonParser(t *testing.T) {
	NewConfigFactory(model.JsonConfigType).CreateParser().Parse([]byte("{}"))
}

func TestCreateJsonGenerator(t *testing.T) {
	v := NewConfigFactory(model.JsonConfigType).CreateGenerator().Generate()
	require.Nil(t, v)
}

func TestCreateYamlParser(t *testing.T) {
	NewConfigFactory(model.YamlConfigType).CreateParser().Parse([]byte("{}"))
}

func TestCreateYamlGenerator(t *testing.T) {
	v := NewConfigFactory(model.YamlConfigType).CreateGenerator().Generate()
	require.Nil(t, v)
}

2.3.3 定义工厂

package abstract_factory

import (
	"godp/02factory/023abstract_factory/json_config"
	"godp/02factory/023abstract_factory/model"
	"godp/02factory/023abstract_factory/yaml_config"
)

// NewConfigFactory 是对 package 外暴露的接口, 外部的 client 可以从这里获取工厂, 而外部的 client 并不需要了解具体实现
func NewConfigFactory(typ model.ConfigType) ConfigFactory {
	switch typ {
	case model.JsonConfigType:
		return &json_config.Factory{}
	case model.YamlConfigType:
		return &yaml_config.Factory{}
	}
	return nil
}

// ConfigFactory 是工厂, 能生产 Config 相关的产品, 如 Parser 或 Generator
type ConfigFactory interface {
	CreateParser() model.Parser
	CreateGenerator() model.Generator
}

2.3.4 定义产品

为了把具体产品放在【子 package】 中,避免循环引用,需要把 产品放在单独的 package 中,如下文的 model package 中。

model/type.go 如下:

package model

// ConfigType 是配置的类型, 据此选择对应的工厂
type ConfigType string

const (
	JsonConfigType ConfigType = "json"
	YamlConfigType ConfigType = "yaml"
)

model/parser.go 定义了第一个产品:

package model

// Parser 是第一种产品, 可以 Parse 某文本, 为某格式
type Parser interface {
	Parse([]byte)
}

model/generator.go 定义了第二个产品:

package model

// Generator 是第二种产品, 可以按照某格式 Generate 某文本
type Generator interface {
	Generate() []byte
}

2.3.5 json config 的实现

json_config/factory.go 定义了json 的具体工厂实现:

package json_config

import (
	"godp/02factory/023abstract_factory/model"
)

type Factory struct {
}

func (f *Factory) CreateParser() model.Parser {
	return &parser{}
}

func (f *Factory) CreateGenerator() model.Generator {
	return &generator{}
}

json_config/parser.go 定义了 json parser 产品的具体实现:

package json_config

// parser 是 json config 的 parser
type parser struct {
}

func (p *parser) Parse([]byte) {

}

json_config/generator.go 定义了 json generator 产品的具体实现:

package json_config

// generator 是 json config 的 generator
type generator struct {
}

func (g *generator) Generate() []byte {
	return nil
}

2.3.6 yaml config 的具体实现:工厂和产品

yaml_config/factory.go 实现具体 yaml 工厂:

package yaml_config

import (
	"godp/02factory/023abstract_factory/model"
)

type Factory struct{}

func (f *Factory) CreateParser() model.Parser {
	return &parser{}
}

func (f *Factory) CreateGenerator() model.Generator {
	return &generator{}
}

yaml_config/parser.go 实现 yaml parser 产品:

package yaml_config

type parser struct {
}

func (p *parser) Parse([]byte) {

}

yaml_config/generator.go 实现 yaml generator 产品:

package yaml_config

type generator struct{}

func (g *generator) Generate() []byte {
	return nil
}