工厂模式

12/5/2021 swift设计模式

# 工厂模式

工厂模式根据抽象程度的不同分为三种:简单工厂模式(也叫静态工厂模式)、工厂方法模式、抽象工厂模式。

# 简单工厂模式

可以根据参数的不同返回不同类的实例。

简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

# Button 样例

enum Style {case mac, win}

protocol Button {}
class MacButton: Button {}
class WinButton: Button {}

class ButtonFactory {
    func createButton(style: Style) -> Button {
        switch style {
        case .mac:
            return MacButton()
        default:
            return WinButton()
        }
    }
}

var style: Style = .mac
var fac = ButtonFactory()
fac.createButton(style: style)

# Shape 样例

protocol Shape {
    func draw()
}

class Rectangle : Shape {
    func draw() {
        print("Draw Rectangle")
    }
}

class Square: Shape {
    func draw() {
        print("Draw Square")
    }
}

class Circle: Square {
    override func draw() {
        print("Draw Circle")
    }
}

class ShapeFactory {
    func getShape(shapeType: String) -> Shape? {
        if shapeType == "CIRCLE" {
            return Circle()
        } else if shapeType == "RECTANGLE" {
            return Rectangle()
        } else if  shapeType == "SQUARE" {
            return Square()
        }
        return nil
    }
}

let facctory = ShapeFactory()
let circle = facctory.getShape(shapeType: "CIRCLE")
circle?.draw()

# 工厂方法模式

工厂方法模式是简单工厂的进一步深化,在工厂方法模式中,不再提供一个统一的工厂类来创建所有的对象,而是针对不同的对象提供不同的工厂。也就是说每个对象都有一个与之对应的工厂。

定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行

# Reader 样例

例如,有一个 Reader 类表示图片读取,另有它的三个子类 JPGReader, PNGReader 和 GIFReader 分别代表 jpg、png 和 gif 读取。

protocol Reader {
    func read()
}

class JPGReader : Reader {
    func read() {
        print("read jpg")
    }
}


class PNGReader: Reader {
    func read() {
        print("read png")
    }
}

class GIFReader: Reader {
    func read() {
        print("read gif")
    }
}

protocol ReaderFactory {
    func getReader() -> Reader
}

class JPGReaderFactory : ReaderFactory {
    func getReader() -> Reader {
        JPGReader()
    }
}

class PNGReaderFactory: ReaderFactory {
    func getReader() -> Reader {
        PNGReader()
    }
}

class GIFReaderFactory: ReaderFactory {
    func getReader() -> Reader {
        GIFReader()
    }
}

var factory: ReaderFactory = GIFReaderFactory()
var reader: Reader = factory.getReader()
reader.read() // read gif

factory = PNGReaderFactory()
reader = factory.getReader()
reader.read() // read png

factory = JPGReaderFactory()
reader = factory.getReader()
reader.read() // read jpg

# Button 样例

例如,有一个 Button 类表示按钮,另有它的两个子类 WinButton 和 MacButton 分别代表 Windows 和 Mac 风格的按钮。

protocol Button {}

class MacButton: Button {}
class WinButton: Button {}

protocol ButtonFactory {
    func createButton() -> Button
}

class WinButtonFactory : ButtonFactory {
    func createButton() -> Button { WinButton() }
}
class MacButtonFactory: ButtonFactory {
    func createButton() -> Button { MacButton() }
}

enum Style {case mac, win}

var style: Style = .mac
var fac: ButtonFactory
switch style {
case .mac:
    fac =  MacButtonFactory()
default:
    fac = WinButtonFactory()
}

fac.createButton()

# 抽象工厂模式

为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。

# 汽车样例

假设我们有两种产品接口 BenzCar、AudiCar 和 BmwCar ,每一种产品都支持多种系列,比如 Sport 系列和 Business 系列。这样每个系列的产品分别是 BenzSportCar, BenzBusinessCar, BmwSportCar, BmwBusinessCar,AudiSportCar,AudiBusinessCar 。为了可以在运行时刻创建一个系列的产品族,我们可以为每个系列的产品族创建一个工厂 SupportDriver 和 BusinessDriver 。每个工厂都有三个方法 createBenzCar ,createBmwCar 和 createAudiCar 并返回对应的产品,可以将这三个方法抽象成一个接口 Driver 。这样在运行时刻我们可以选择创建需要的产品系列

class BenzCar {
    var name: String
    init(name: String) {
        self.name = name
    }

    func drive() {}
}

class BenzSportCar : BenzCar {
    override func drive() {
        print("\(name) :: BenzSportCart")
    }
}

class BenzBusinessCar : BenzCar {
    override func drive() {
        print("\(name) :: BenzBusinessCar")
    }
}


class BmwCar {
    var name: String

    init(name: String) {
        self.name = name
    }

    func drive() {}
}

class BmwSportCar : BmwCar {
    override func drive() {
        print("\(name) :: BmwCSportCart")
    }
}

class BmwBusinessCar : BmwCar {
    override func drive() {
        print("\(name) :: BmwBusinessCar")
    }
}

class AudiCar {
    var name: String

    init(name: String) {
        self.name = name
    }

    func drive() {}
}

class AudiSportCar : AudiCar {
    override func drive() {
        print("\(name) :: AudiCSportCart")
    }
}

class AudiBusinessCar : AudiCar {
    override func drive() {
        print("\(name) :: AudiBusinessCar")
    }
}


protocol Driver {
    func createBenzCar(car: String) -> BenzCar
    func createBmwCar(car: String) -> BmwCar
    func createAudiCar(car: String) -> AudiCar
}

class SupportDriver : Driver {

    func createBenzCar(car: String) -> BenzCar {
        BenzSportCar.init(name: car)
    }

    func createBmwCar(car: String) -> BmwCar {
        BmwSportCar.init(name: car)
    }

    func createAudiCar(car: String) -> AudiCar {
        AudiSportCar.init(name: car)
    }
}


class BusinessDriver: Driver {
    func createBenzCar(car: String) -> BenzCar {
        BenzBusinessCar.init(name: car)
    }

    func createBmwCar(car: String) -> BmwCar {
        BmwBusinessCar.init(name: car)
    }

    func createAudiCar(car: String) -> AudiCar {
        AudiBusinessCar.init(name: car)
    }
}

let driver = BusinessDriver()
let car = driver.createAudiCar(car: "BusinessDriver")
car.drive()

# GUI 样例

假设我们有两种产品接口 Button 和 Border ,每一种产品都支持多种系列,比如 Mac 系列和 Windows 系列。这样每个系列的产品分别是 MacButton, WinButton, MacBorder, WinBorder 。为了可以在运行时刻创建一个系列的产品族,我们可以为每个系列的产品族创建一个工厂 MacFactory 和 WinFactory 。每个工厂都有两个方法 CreateButton 和 CreateBorder 并返回对应的产品,可以将这两个方法抽象成一个接口 AbstractFactory 。这样在运行时刻我们可以选择创建需要的产品系列

protocol Button {}

class MacButton: Button {}
class WinButton: Button {}

protocol Border {}
class MacBorder: Border {}
class WinBorder: Border {}

protocol AbstractFactory {
    func createButton() -> Button
    func createBorder() -> Border
}

class MacFactory: AbstractFactory {
    func createButton() -> Button { MacButton() }
    func createBorder() -> Border { MacBorder() }
}

class WinFactory: AbstractFactory {
    func createButton() -> Button { WinButton() }
    func createBorder() -> Border { WinBorder() }
}

enum Style { case mac, win}

var fac: AbstractFactory
var style: Style = .mac

switch style {
case .mac:
    fac = MacFactory()
default:
    fac = WinFactory()
}

let button: Button = fac.createButton()
let border: Border = fac.createBorder()

# 三者对比

简单工厂 工厂方法 抽象工厂
特点 使用静态方法通过接受参数的不同来返回不同的实例 针对每一种产品提供一个工厂类 针对产品族
扩展方式 在不修改代码的前提下无法扩展 在同一级别中可以任意扩展 应对产品族的概念,可以增加新的产品线,但无法增加新的产品
优点 在于工厂类中包含了必要的逻辑,更具客户需要的条件动态实例化相关的类,对客户端来说,去掉了与具体产品的依赖 创建对象的接口,让子类去决定具体的实例化的对象,把简单的内部逻辑判断移到了客户端代码。工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点。 分离了具体的类,抽象工厂模式帮助你控制一个应用创建的对象的类,客户通过他们的抽象接口操纵实例,产品的类名也在具体工厂的实现中被分离,它们不出现在客户代码中。它使得易于交换产品系列。
缺点 工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,当增加新的产品时,会违反开发-封闭原则 不易于维护,假如某个具体的产品类需要进行一定的修改,很可能需要修改对应的工厂类。当同时需要修改多个产品类的时候,对工厂类的修改会变得相当麻烦 抽象工厂模式在于难于应对“新对象”的需求变动,难以支持新种类产品,难以扩展抽象工厂以生产新种类产品
上次更新: 12/6/2021, 5:24:18 PM