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


二、工厂

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

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

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

源码详见:godp/02factory at master · datager/godp · GitHub

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 json_yaml_parse_factory

2.3.1.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.1.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.1.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.1.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.1.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.1.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
}

2.3.2 os_software_factory

详见设计模式之禅第九章, os 有很多软件, 各 os 的软件界面都各不相同. 例如 mac 的关闭/最小化/最大化在左上角, windows 的关闭/最小化/最大化在右上角.

因此, mac 是一个产品族, windows 是一个产品族. 即 mac 需要一个 软件工厂, windows 需要一个软件工厂. 这种一个工厂能生产多个产品(如 IDE/浏览器/终端)的, 就称为抽象工厂.

02factory/023abstract_factory/0232os_software_factory
├── browser.go
├── ide.go
├── mac_os_software_factory.go
├── os_software_factory.go
├── os_software_factory_test.go
├── readme.md
├── software.go
└── windows_os_software_factory.go
2.3.2.1 os_software_factory_test.go
package _232os_software_factory

import "testing"

/*
=== RUN   TestOsSoftwareFactory
mac 打开 vscode
vscode 调试
windows 打开 jetbrains
jetbrains 运行
windows 打开 jetbrains
jetbrains 最小化
windows 打开 jetbrains
jetbrains 最大化
windows 打开 jetbrains
jetbrains 关闭
--- PASS: TestOsSoftwareFactory (0.00s)
PASS
*/
func TestOsSoftwareFactory(t *testing.T) {
	NewOsSoftwareFactory(OSTypeMac).createIDE(IDETypeVscode).debug()
	NewOsSoftwareFactory(OSTypeWindows).createIDE(IDETypeJetbrains).run()
	NewOsSoftwareFactory(OSTypeWindows).createIDE(IDETypeJetbrains).minimize()
	NewOsSoftwareFactory(OSTypeWindows).createIDE(IDETypeJetbrains).maximize()
	NewOsSoftwareFactory(OSTypeWindows).createIDE(IDETypeJetbrains).close()
}
2.3.2.2 os_software_factory.go
package _232os_software_factory

type osSoftwareFactory interface {
	createIDE(t string) ide
	createBrowser(t string) browser
}

const (
	OSTypeMac     = "mac"
	OSTypeWindows = "windows"
)

func NewOsSoftwareFactory(t string) osSoftwareFactory {
	switch t {
	case OSTypeMac:
		return &macSoftwareFactory{}
	case OSTypeWindows:
		return &windowsSoftwareFactory{}
	}
	panic("invalid os type" + t)
}
2.3.2.3 mac_os_software_factory.go
package _232os_software_factory

import "fmt"

type macSoftwareFactory struct{}

func (f *macSoftwareFactory) createIDE(t string) ide {
	switch t {
	case IDETypeVscode:
		fmt.Println("mac 打开 vscode")
		return &vscode{}
	case IDETypeJetbrains:
		fmt.Println("mac 打开 jetbrains")
		return &jetbrains{}
	}
	panic("invalid ide type" + t)
}

func (f *macSoftwareFactory) createBrowser(t string) browser {
	switch t {
	case BrowserTypeChrome:
		fmt.Println("mac 打开 chrome")
		return &chrome{}
	case BrowserTypeFirefox:
		fmt.Println("mac 打开 firefox")
		return &firefox{}
	}
	panic("invalid browser type" + t)
}
2.3.2.4 windows_os_software_factory.go
package _232os_software_factory

import "fmt"

type windowsSoftwareFactory struct{}

func (f *windowsSoftwareFactory) createIDE(t string) ide {
	switch t {
	case IDETypeVscode:
		fmt.Println("windows 打开 vscode")
		return &vscode{}
	case IDETypeJetbrains:
		fmt.Println("windows 打开 jetbrains")
		return &jetbrains{}
	}
	panic("invalid ide type" + t)
}

func (f *windowsSoftwareFactory) createBrowser(t string) browser {
	switch t {
	case BrowserTypeChrome:
		fmt.Println("windows 打开 chrome")
		return &chrome{}
	case BrowserTypeFirefox:
		fmt.Println("windows 打开 firefox")
		return &firefox{}
	}
	panic("invalid browser type" + t)
}
2.3.2.5 software.go
package _232os_software_factory

type software interface {
	// 最小化
	minimize()
	// 最大化
	maximize()
	// 关闭
	close()
}
2.3.2.6 ide.go
package _232os_software_factory

import "fmt"

type ide interface {
	software
	// 运行
	run()
	// 调试
	debug()
}

const (
	IDETypeVscode    = "vscode"
	IDETypeJetbrains = "jetbrains"
)

type vscode struct{}

func (i *vscode) minimize() {
	fmt.Println("vscode 最小化")
}

func (i *vscode) maximize() {
	fmt.Println("vscode 最大化")
}

func (i *vscode) close() {
	fmt.Println("vscode 关闭")
}

func (i *vscode) run() {
	fmt.Println("vscode 运行")
}

func (i *vscode) debug() {
	fmt.Println("vscode 调试")
}

type jetbrains struct{}

func (i *jetbrains) minimize() {
	fmt.Println("jetbrains 最小化")
}

func (i *jetbrains) maximize() {
	fmt.Println("jetbrains 最大化")
}

func (i *jetbrains) close() {
	fmt.Println("jetbrains 关闭")
}

func (i *jetbrains) run() {
	fmt.Println("jetbrains 运行")
}

func (i *jetbrains) debug() {
	fmt.Println("jetbrains 调试")
}
2.3.2.7 browser.go
package _232os_software_factory

import "fmt"

type browser interface {
	software
	// 搜索
	search()
	// 下载
	download()
}

const (
	BrowserTypeChrome  = "chrome"
	BrowserTypeFirefox = "firefox"
)

type chrome struct{}

func (i *chrome) minimize() {
	fmt.Println("chrome 最小化")
}

func (i *chrome) maximize() {
	fmt.Println("chrome 最大化")
}

func (i *chrome) close() {
	fmt.Println("chrome 关闭")
}

func (i *chrome) search() {
	fmt.Println("chrome 搜索")
}

func (i *chrome) download() {
	fmt.Println("chrome 下载")
}

type firefox struct{}

func (i *firefox) minimize() {
	fmt.Println("firefox 最小化")
}

func (i *firefox) maximize() {
	fmt.Println("firefox 最大化")
}

func (i *firefox) close() {
	fmt.Println("firefox 关闭")
}

func (i *firefox) search() {
	fmt.Println("firefox 搜索")
}

func (i *firefox) download() {
	fmt.Println("firefox 下载")
}
  • 30
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呆呆的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值