創(chuàng)建者模式-建造者模式(The Builder Pattern)

本文大部分內(nèi)容翻譯至《Pro Design Pattern In Swift》By Adam Freeman,一些地方做了些許修改,并將代碼升級到了Swift2.0,翻譯不當(dāng)之處望多包涵。

建造者模式(The Builder Pattern)

建造者模式用來將對象的配置從創(chuàng)建中分離出來。請求組件有配置數(shù)據(jù)并將它傳遞給中間人-建造者-它負(fù)責(zé)創(chuàng)建代表組件的對象。建造者模式它可以將復(fù)雜對象的建造過程抽象出來(抽象類別),使這個(gè)抽象過程的不同實(shí)現(xiàn)方法可以構(gòu)造出不同表現(xiàn)(屬性)的對象。


示例工程

OS X Command Line Tool工程:

Food.swift

class Burger {
    
    let customerName:String
    let veggieProduct:Bool
    let patties:Int
    let pickles:Bool
    let mayo:Bool
    let ketchup:Bool
    let lettuce:Bool
    let cook:Cooked
    
    enum Cooked : String {
        case RARE = "Rare"
        case NORMAL = "Normal"
        case WELLDONE = "Well Done"
    }
    
    init(name:String, veggie:Bool, patties:Int, pickles:Bool, mayo:Bool,
        ketchup:Bool, lettuce:Bool, cook:Cooked) {
        self.customerName = name
        self.veggieProduct = veggie
        self.patties = patties
        self.pickles = pickles
        self.mayo = mayo
        self.ketchup = ketchup
        self.lettuce = lettuce
        self.cook = cook
    }
    
    func printDescription() {
        print("Name \(self.customerName)")
        print("Veggie: \(self.veggieProduct)")
        print("Patties: \(self.patties)")
        print("Pickles: \(self.pickles)")
        print("Mayo: \(self.mayo)")
        print("Ketchup: \(self.ketchup)")
        print("Lettuce: \(self.lettuce)")
        print("Cook: \(self.cook.rawValue)")
    }
}

接下來main.swift

main.swift

let order = Burger(name: "Joe", veggie: false, patties: 2, pickles: true,
    mayo: true, ketchup: true, lettuce: true, cook: Burger.Cooked.NORMAL)
order.printDescription()

運(yùn)行程序:

Name Joe
Veggie: false
Patties: 2
Pickles: true
Mayo: true
Ketchup: true
Lettuce: true
Cook: Normal

理解建造者模式解決的問題

當(dāng)一個(gè)對象需要大量的配置數(shù)據(jù)的時(shí)候,建造者模式出現(xiàn)了。在上面的例子中,Burger類的初始化方法就要求每一個(gè)方面的配置數(shù)據(jù)。下面的是虛構(gòu)的餐館預(yù)定漢堡包過程:

  1. 服務(wù)員問顧客的姓名
  2. 服務(wù)員問顧客是否需要素食
  3. 服務(wù)員問顧客是否要定做漢堡包
  4. 服務(wù)員問顧客是否要升級買一個(gè)額外的肉餅

上面只有4個(gè)步驟,但卻拋出了一些問題。其實(shí)我們在創(chuàng)建Burger對象的時(shí)候是這樣的:

main.swift

// Step 1 - Ask for name
let name = "Joe"
// Step 2 - Is veggie meal required?
let veggie = false
// Step 3 - Customize burger?
let pickles = true
let mayo = false
let ketchup = true
let lettuce = true
// Step 4 - Buy additional patty?
let patties = 2
let cooked = Burger.Cooked.NORMAL

let order = Burger(name: name, veggie: veggie, patties: patties, pickles: pickles, mayo: mayo, ketchup: ketchup, lettuce: lettuce, cook: cooked)
order.printDescription()

Burger類的初始化方法要求請求組件知道默認(rèn)的值當(dāng)顧客不想改變Burger的配置的時(shí)候。每一個(gè)請求組件都必須知道這個(gè)事情,那就意味著如果改變一個(gè)默認(rèn)的值,那么就必須改變每一個(gè)請求組件。


理解建造者模式

建造者模式解決這個(gè)問題通過引出一個(gè)中間人-建造者-在請求組件和需要?jiǎng)?chuàng)建的對象之間。



實(shí)現(xiàn)建造者模式

1. 定義創(chuàng)建者類

首先,就是創(chuàng)建建造者類,建造者類提供了Burger類參數(shù)的默認(rèn)值并且允許請求組件去改變這些值。

Builder.swift

class BurgerBuilder {
    private var veggie  = false
    private var pickles = true
    private var mayo    = true
    private var ketchup = true
    private var lettuce = true
    private var cooked  = Burger.Cooked.NORMAL
    private var patties = 2
    
    func setVeggie(choice: Bool)  { self.veggie  = choice }
    func setPickles(choice: Bool) { self.pickles = choice }
    func setMayo(choice: Bool)    { self.mayo    = choice }
    func setKetchup(choice: Bool) { self.ketchup = choice }
    func setLettuce(choice: Bool) { self.lettuce = choice }
    func setCooked(choice: Burger.Cooked) { self.cooked = choice }
    func addPatty(choice: Bool)   { self.patties = choice ? 3 : 2 }
    
    func buildObject() -> Burger{
        return Burger(name: name, veggie: veggie, patties: patties, pickles: pickles, mayo: mayo, ketchup: ketchup, lettuce: lettuce, cook: cooked)
    }
    
}

2. 使用建造者

main.swift

var builder = BurgerBuilder()
// Step 1 - Ask for name
let name = "Joe"
// Step 2 - Is veggie meal required?
builder.setVeggie(false)
// Step 3 - Customize burger?
builder.setMayo(false)
builder.setCooked(Burger.Cooked.WELLDONE)
// Step 4 - Buy additional patty?
builder.addPatty(false)
let order = builder.buildObject(name)
order.printDescription()

運(yùn)行程序,輸出:

Name Joe
Veggie: false
Patties: 2
Pickles: true
Mayo: false
Ketchup: true
Lettuce: true
Cook: Well Done

建造者模式的變形

你可以將建造者模式和其他模式結(jié)合起來,一般是和工廠方法模式和抽象工廠模式。用得最多的就是定義復(fù)數(shù)的建造者并且讓它們都實(shí)現(xiàn)工廠方法模式。

Builder.swift

enum Burgers {
    case STANDARD
    case BIGBURGER
    case SUPERVEGGIE
}

class BurgerBuilder {
    private var veggie  = false
    private var pickles = true
    private var mayo    = true
    private var ketchup = true
    private var lettuce = true
    private var cooked  = Burger.Cooked.NORMAL
    private var patties = 2
    private var bacon   = true
    
    private init() {
        // do nothing
    }
    
    func setVeggie(choice: Bool)  {
        self.veggie = choice
        if (choice) {
            self.bacon = false
        }
    }
    func setPickles(choice: Bool) { self.pickles = choice }
    func setMayo(choice: Bool)    { self.mayo    = choice }
    func setKetchup(choice: Bool) { self.ketchup = choice }
    func setLettuce(choice: Bool) { self.lettuce = choice }
    func setCooked(choice: Burger.Cooked) { self.cooked = choice }
    func addPatty(choice: Bool)   { self.patties = choice ? 3 : 2 }
    func setBacon(choice: Bool)   { self.bacon   = choice }
    
    func buildObject(name:String) -> Burger{
        return Burger(name: name, veggie: veggie, patties: patties, pickles: pickles, mayo: mayo, ketchup: ketchup, lettuce: lettuce, cook: cooked,bacon: bacon)
    }
    
    class func getBuilder(burgerType:Burgers) -> BurgerBuilder {
        var builder:BurgerBuilder
        switch (burgerType) {
            case .BIGBURGER: builder   = BigBurgerBuilder()
            case .SUPERVEGGIE: builder = SuperVeggieBurgerBuilder()
            case .STANDARD: builder    = BurgerBuilder()
        }
        return builder
    }
    
}

class BigBurgerBuilder : BurgerBuilder {
    private override init() {
        super.init()
        self.patties = 4
        self.bacon = false
    }
        
    override func addPatty(choice: Bool) {
        fatalError("Cannot add patty to Big Burger")
    }
}

class SuperVeggieBurgerBuilder : BurgerBuilder {
    private override init() {
        super.init()
        self.veggie = true
        self.bacon = false
    }
        
    override func setVeggie(choice: Bool) {
        // do nothing - always veggie
    }
        
    override func setBacon(choice: Bool) {
        fatalError("Cannot add bacon to this burger")
    }
}

接著是:

main.swift

// Step 1 - Ask for name
let name = "Joe"

// Step 2 - Select a Product
let builder = BurgerBuilder.getBuilder(Burgers.BIGBURGER)

// Step 3 - Customize burger?
builder.setMayo(false)
builder.setCooked(Burger.Cooked.WELLDONE)

let order = builder.buildObject(name)
order.printDescription()

運(yùn)行程序,輸出:

Name Joe
Veggie: false
Patties: 4
Pickles: true
Mayo: false
Ketchup: true
Lettuce: true
Cook: Well Done

Cocoa中的建造者模式

Cocoa中最常用的使用的建造者模式的類就是 NSDateComponents類,NSDateComponents類允許請求組件設(shè)置值來創(chuàng)建 NSDate類。請看下面例子:

import Foundation
var builder = NSDateComponents()

builder.hour = 10
builder.day = 6
builder.month = 9
builder.year = 1940
builder.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)

var date = builder.date
print(date!)

運(yùn)行程序,輸出:

1940-09-06 01:00:00 +0000
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,724評論 19 139
  • 沒有人買車會(huì)只買一個(gè)輪胎或者方向盤,大家買的都是一輛包含輪胎、方向盤和發(fā)動(dòng)機(jī)等多個(gè)部件的完整汽車。如何將這些部件組...
    justCode_閱讀 2,011評論 1 6
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,843評論 4 61
  • 在公園散步 在樹下談心 在商場閑逛 手拉著手 喜歡你騎車載我回家 摟著你的腰 這畫面曾經(jīng)是我羨慕的 羨慕著別人一起...
    追求快樂閱讀 619評論 0 1
  • 在以前的博文中談了自己對用戶成熟度的一些看法以及不成熟用戶的一些表現(xiàn)。最近回了一趟老家,再度讓我思考用戶成熟度的問...
    馬虎眼閱讀 1,094評論 0 19

友情鏈接更多精彩內(nèi)容