![](https://i-blog.csdnimg.cn/blog_migrate/4e588314691c34a1736e2b37d30b2e79.png)
二、工厂
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 下载")
}