15.1 简单工厂模式

简单工厂模式 (simple factory pattern) 是软件开发中使用的最频繁的设计模式之一, 它属于创建型模式, 使用简单工厂模式时, 创建对象将通过统一的入口函数来操作, 入口函数根据所要创建的对象类型调用具体的创建函数, 对于外层的调用者来说只需传入对象的类型 (或相应参数), 而不必直接去调用特定的创建函数

package main

import "fmt"

// 产品接口
type Computer interface {
    Create()
}

// 工厂结构体
// 这里即是创建产品的「工厂」
// 所有产品都由这个工厂来创建, 根据传入的参数不同, 该工厂将直接创建不同的产品
type ComputerFactory struct {
}

func (c *ComputerFactory) NewComputer(factoryName string) Computer {
    if factoryName == "Apple" {
        return &appleInc{}
    } else if factoryName == "HUAWEI" {
        return &huaweiInc{}
    }
    return nil
}

// 产品结构体 1
type apple struct {
}

func (*apple) Create() {
    fmt.Println("Apple create macbook")
}

// 产品结构体 2
type huawei struct {
}

func (*huawei) Create() {
    fmt.Println("HUAWEI create matebook")
}

func main() {
    computerFactory := new(ComputerFactory)

    // 根据传入的参数不同初始化不同的示例
    p1 := computerFactory.NewComputer("Apple")
    p1.Create()

    p2 := computerFactory.NewComputer("HUAWEI")
    p2.Create()
}

在这个例子中, 包外的调用者只需调用 NewComputer 函数并传入相应的参数即可创建对应的对象, 而具体的创建方法在包外是不可见的, 即做到了实现细节的封装。一般说来, 在 Go 中当我们使用 NewXXX 的方式创建对象/接口时, 当其返回为接口时便是简单工厂模式, 在简单工厂模式中, 根据传入参数的不同将直接创建不同的实例

15.2 工厂方法模式

简单工厂模式通过统一的创建函数传入不同参数来创建不同的实例确实带来了一定的便利性, 但有个问题是每当我们要增加一种新的产品时, 都需要修改统一的创建函数, 增加相应的参数, 这里存在较为紧密的耦合, 而工厂方法模式 (factory method pattern) 中, 我们可以创建一个工厂接口, 通过实现工厂接口创建多种工厂, 这样使得对象的创建由一个对象负责所有具体类的实例化改为了由多个子类来负责对具体类的实例化, 显然, 工厂方法模式也属于创建型模式

package main

import "fmt"

// 工厂接口
type Factory interface {
    CreateComputer() ComputerProduct
}

// 产品接口
type ComputerProduct interface {
    // 品牌
    Brand()
    // 内存(以 GB 为单位)
    Memory()
}

// 工厂结构体 1
type AppleFactory struct {
}

func (a *AppleFactory) CreateComputer() ComputerProduct {
    return &MacBook{}
}

type MacBook struct {
}

func (m *MacBook) Brand() {
    fmt.Println("apple")
}

func (m *MacBook) Memory() {
    fmt.Println(16)
}

// 工厂结构体 2
type HuaweiFactory struct {
}

func (h *HuaweiFactory) CreateComputer() ComputerProduct {
    return &MateBook{}
}

type MateBook struct {
}

func (m *MateBook) Brand() {
    fmt.Println("HUAWEI")
}

func (m *MateBook) Memory() {
    fmt.Println(8)
}

func main() {
    // 创建工厂 1
    f1 := new(AppleFactory)
    p1 := f1.CreateComputer()
    p1.Brand()
    p1.Memory()

    // 创建工厂 2
    f2 := new(HuaweiFactory)
    p2 := f2.CreateComputer()
    p2.Brand()
    p2.Memory()
}

通过这个示例可以看到, 工厂方法模式并不是在一个工厂实例中根据参数不同去直接创建对应的产品, 而是将工厂定义为一个接口, 不同的工厂去实现这个接口, 对于工厂方法模式来说, 需要工厂接口、工厂结构体、产品接口和产品结构体, 虽然做到了解耦, 但也增加了代码量

15.3 抽象工厂模式

抽象工厂模式 (abstract factory pattern) 是工厂方法模式的延伸, 在工厂方法模式中, 每个工厂只生产一种特定的商品, 而抽象工厂模式用于生产产品族的工厂, 位于一个产品族之间的产品是有关联的, 我们通过下面的例子来具体说明抽象工厂模式

package main

import "fmt"

type Phone interface {
    Phone()
}

type Pad interface {
    Pad()
}

// 工厂接口
type ITFactory interface {
    CreatePhone() Phone
    CreatePad() Pad
}

// 具体的 apple 工厂
type appleFactory struct {
}

func (a *appleFactory) CreatePhone() Phone {
    return &iPhone{}
}

func (a *appleFactory) CreatePad() Pad {
    return &iPad{}
}

type iPhone struct {
}

func (i *iPhone) Phone() {
    fmt.Println("iphone")
}

type iPad struct {
}

func (i *iPad) Pad() {
    fmt.Println("ipad")
}

// 具体的华为工厂
type huaweiFactory struct {
}

func (h *huaweiFactory) CreatePhone() Phone {
    return &mate40{}
}

func (h *huaweiFactory) CreatePad() Pad {
    return &matePad{}
}

type mate40 struct {
}

func (m *mate40) Phone() {
    fmt.Println("mate40")
}

type matePad struct {
}

func (m *matePad) Pad() {
    fmt.Println("matePad")
}

func main() {
    // 创建工厂 1
    f1 := new(appleFactory)
    p11 := f1.CreatePad()
    p11.Pad()
    p12 := f1.CreatePhone()
    p12.Phone()

    // 创建工厂 2
    f2 := new(huaweiFactory)
    p21 := f2.CreatePad()
    p21.Pad()
    p22 := f2.CreatePhone()
    p22.Phone()
}