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

慈云数据 1年前 (2024-04-08) 技术支持 68 0

文章目录

  • 二、工厂
    • 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

          【设计模式】2、工厂:简单工厂、工厂方法、抽象工厂
          (图片来源网络,侵删)

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

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

          【设计模式】2、工厂:简单工厂、工厂方法、抽象工厂
          (图片来源网络,侵删)

          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
            }
            
微信扫一扫加客服

微信扫一扫加客服