根据条件对外提供创建不同的类。仿佛根据顾客要求,工厂生产不同的产品。
Go 语言没有构造函数,一般会定义 NewXXX 函数来初始化相关类。NewXXX 函数返回接口时就是简单工厂模式。
一个简单的应用场景,这个应用场景里会提供很多语言的打印机,他们都源于一个 Printer 接口。
// Printer 简单工厂要返回的接口类型
type Printer interface {
Print(name string) string
}
程序通过简单工厂向客户端提供需要的语种的打印机。
func NewPrinter(lang string) Printer {
switch lang {
case "cn":
return new(CnPrinter)
case "en":
return new(EnPrinter)
default:
return new(CnPrinter)
}
}
目前这个场景里我们先提供两个语种的打印机,他们都是 Printer 接口的具体实现类型。
// CnPrinter 是 Printer 接口的实现,它说中文
type CnPrinter struct {}
func (*CnPrinter) Print(name string) string {
return fmt.Sprintf("你好, %s", name)
}
// EnPrinter 是 Printer 接口的实现,它说中文
type EnPrinter struct {}
func (*EnPrinter) Print(name string) string {
return fmt.Sprintf("Hello, %s", name)
}
客户端只需要告诉工厂想要哪个语种的打印机产品,工厂就会把产品给返回给客户端。
printer := NewPrinter("en")
fmt.Println(printer.Print("Bob"))
简单工厂模式主要包含3个角色。
简单工厂的优点是,简单,缺点是如果具体产品扩产,就必须修改工厂内部,增加Case,一旦产品过多就会导致简单工厂过于臃肿,为了解决这个问题,才有了下一级别的工厂模式–工厂方法。
工厂方法模式(Factory Method Pattern)又叫作多态性工厂模式,指定义一个创建对象的接口,但由实现这个接口的工厂类来决定实例化哪个产品类,工厂方法把类的实例化推迟到子类中进行。
在工厂方法模式中,不再由单一的工厂类生产产品,而是由工厂类的子类实现具体产品的创建。
即把同一类型的不同工厂类的共同属性、方法进一步抽象出一个母工厂,和母类。
因此,当增加一个产品时,只需增加一个相应的工厂类的子类, 以解决简单工厂生产太多产品时导致其内部代码臃肿(switch … case分支过多)的问题。
下面举个简单的例子来理解工厂方法的设计思想,考虑有这样一个生产计算器的工厂,每类计算器产品都由一个子工厂负责生产。
Go中没有继承,所以这里说的工厂子类,其实是直接实现工厂接口的具体工厂类
// OperatorFactory 工厂接口,由具体工厂类来实现
type OperatorFactory interface {
Create() MathOperator
}
// MathOperator 实际产品实现的接口--表示数学运算器应该有哪些行为
type MathOperator interface {
SetOperandA(int)
SetOperandB(int)
ComputeResult() int
}
假定程序可以生产两类计算器,加法计算器和乘法计算器,也就是在工厂方法模式中,存在两个子类工厂。
//PlusOperatorFactory 是 PlusOperator 加法运算器的工厂类
type PlusOperatorFactory struct{}
func (pf *PlusOperatorFactory) Create() MathOperator {
return &PlusOperator{
BaseOperator: &BaseOperator{},
}
}
// MultiOperatorFactory 是乘法运算器产品的工厂
type MultiOperatorFactory struct {}
func (mf *MultiOperatorFactory) Create() MathOperator{
return &MultiOperator{
BaseOperator: &BaseOperator{},
}
}
这两个子类工厂分别用来生产加法和乘法计算器
// BaseOperator 是所有 Operator 的基类
// 封装公用方法,因为Go不支持继承,具体Operator类
// 只能组合它来实现类似继承的行为表现。
type BaseOperator struct {
operandA, operandB int
}
func (o *BaseOperator) SetOperandA(operand int) {
o.operandA = operand
}
func (o *BaseOperator) SetOperandB(operand int) {
o.operandB = operand
}
//PlusOperatorFactory 是 PlusOperator 加法运算器的工厂类
type PlusOperatorFactory struct{}
func (pf *PlusOperatorFactory) Create() MathOperator {
return &PlusOperator{
BaseOperator: &BaseOperator{},
}
}
//PlusOperator 实际的产品类--加法运算器
type PlusOperator struct {
*BaseOperator
}
//ComputeResult 计算并获取结果
func (p *PlusOperator) ComputeResult() int {
return p.operandA + p.operandB
}
// MultiOperatorFactory 是乘法运算器产品的工厂
type MultiOperatorFactory struct {}
func (mf *MultiOperatorFactory) Create() MathOperator{
return &MultiOperator{
BaseOperator: &BaseOperator{},
}
}
// MultiOperator 实际的产品类--乘法运算器
type MultiOperator struct {
*BaseOperator
}
func (m *MultiOperator) ComputeResult() int {
return m.operandA * m.operandB
}
测试运行–客户端使用子类工厂创建产品实例。
func main() {
var factory OperatorFactory
var mathOp MathOperator
factory = &PlusOperatorFactory{}
mathOp = factory.Create()
mathOp.SetOperandB(3)
mathOp.SetOperandA(2)
fmt.Printf("Plus operation reuslt: %d\n", mathOp.ComputeResult())
factory= &MultiOperatorFactory{}
mathOp = factory.Create()
mathOp.SetOperandB(3)
mathOp.SetOperandA(2)
fmt.Printf("Multiple operation reuslt: %d\n", mathOp.ComputeResult())
}
工厂方法模式的优点
工厂方法模式的缺点
即对于更大的项目,具有更多的不同类型的类,此时把所有工厂类的共同属性进一步抽象出一个包含不同类型工厂的公共母工厂。
example:抽象工厂有两个实际工厂类一个是华为的工厂,一个是小米的工厂,他们用来实际生产自家的产品设备。
抽象工厂也具备工厂方法把产品的创建推迟到工厂子类去做的特性,假如未来加入了 VIVO 的产品,我们就可以通过再创建 VIVO 工厂子类来扩展。
type AbstractFactory interface {
CreateTelevision() ITelevision
CreateAirConditioner() IAirConditioner
}
type ITelevision interface {
Watch()
}
type IAirConditioner interface {
SetTemperature(int)
}
type HuaWeiFactory struct{}
func (hf *HuaWeiFactory) CreateTelevision() ITelevision {
return &HuaWeiTV{}
}
func (hf *HuaWeiFactory) CreateAirConditioner() IAirConditioner {
return &HuaWeiAirConditioner{}
}
type HuaWeiTV struct{}
func (ht *HuaWeiTV) Watch() {
fmt.Println("Watch HuaWei TV")
}
type HuaWeiAirConditioner struct{}
func (ha *HuaWeiAirConditioner) SetTemperature(temp int) {
fmt.Printf("HuaWei AirConditioner set temperature to %d ℃\n", temp)
}
type MiFactory struct{}
func (mf *MiFactory) CreateTelevision() ITelevision {
return &MiTV{}
}
func (mf *MiFactory) CreateAirConditioner() IAirConditioner {
return &MiAirConditioner{}
}
type MiTV struct{}
func (mt *MiTV) Watch() {
fmt.Println("Watch HuaWei TV")
}
type MiAirConditioner struct{}
func (ma *MiAirConditioner) SetTemperature(temp int) {
fmt.Printf("Mi AirConditioner set temperature to %d ℃\n", temp)
}
func main() {
var factory AbstractFactory
var tv ITelevision
var air IAirConditioner
factory = &HuaWeiFactory{}
tv = factory.CreateTelevision()
air = factory.CreateAirConditioner()
tv.Watch()
air.SetTemperature(25)
factory = &MiFactory{}
tv = factory.CreateTelevision()
air = factory.CreateAirConditioner()
tv.Watch()
air.SetTemperature(26)
}
抽象工厂模式的优点
抽象工厂模式的缺点
参考:公众号陪计算机度过漫长岁月