結(jié)構(gòu)模式-復(fù)合模式(The Composite Pattern)

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

復(fù)合模式(The Composite Pattern)

復(fù)合模式將對(duì)象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu),它使得客戶對(duì)單個(gè)對(duì)象和復(fù)合對(duì)象的使用具有一致性。


示例工程

OS X Command Line Tool工程:

CarParts.swift

class Part {
    let name:String
    let price:Float
    
    init(name:String, price:Float) {
        self.name = name
        self.price = price
    }
}

class CompositePart {
    let name:String
    let parts:[Part]
        
    init(name:String, parts:Part...) {
        self.name = name
        self.parts = parts;
    }
}

我們定義了兩個(gè)汽車零件類用來修理汽車。Part類代表獨(dú)立的汽車零件,例如輪胎。 CompositePart 代表一些列組合而成的零件,例如包含輪胎的車輪。 CompositePart 包含了一個(gè)Part元素構(gòu)成的數(shù)組,用來代表構(gòu)成復(fù)合零件的各個(gè)獨(dú)立零件。

Orders.swift

import Foundation

class CustomerOrder {
    let customer:String
    let parts:[Part]
    let compositeParts:[CompositePart]
    
    init(customer:String, parts:[Part], composites:[CompositePart]) {
        self.customer = customer
        self.parts = parts
        self.compositeParts = composites
    }
    
    var totalPrice:Float {
        
        let total = parts.reduce(0){
            subtotal,part -> Float in
             return subtotal + part.price
        }
        
        
        return compositeParts.reduce(total){
            subtotal,cpart -> Float in
                return cpart.parts.reduce(subtotal){
                    tmptotal,tmpart -> Float in
                        return tmptotal + tmpart.price
                }
        }
    }
    
    func printDetails() {
        print("Order for \(customer): Cost: \(formatCurrencyString(totalPrice))")
    }
    
    func formatCurrencyString(number:Float) -> String {
        let formatter = NSNumberFormatter()
        formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
        return formatter.stringFromNumber(number) ?? ""
    }
}

CustomerOrder 類代表Part和CompositePart對(duì)象的一個(gè)訂單。

main.swift

let doorWindow = CompositePart(name: "DoorWindow", parts:
    Part(name: "Window", price: 100.50),
    Part(name: "Window Switch", price: 12))
let door = CompositePart(name: "Door", parts:
    Part(name: "Window", price: 100.50),
    Part(name: "Door Loom", price: 80),
    Part(name: "Window Switch", price: 12),
    Part(name: "Door Handles", price: 43.40))
let hood = Part(name: "Hood", price: 320)
let order = CustomerOrder(customer: "Bob", parts: [hood],
    composites: [door, doorWindow])

order.printDetails()

運(yùn)行程序,得到下面輸出:

Order for Bob: Cost: ¥ 668.40

理解復(fù)合模式解決的問題

示例工程顯示了兩個(gè)不同的問題:

第一個(gè)問題是我們限制了零件的層級(jí)。當(dāng)我們創(chuàng)建一個(gè)CompositePart來代表車門時(shí),不得不去創(chuàng)建Part對(duì)象代表車窗和車窗開關(guān)。同時(shí)當(dāng)我們創(chuàng)建車門窗時(shí)又創(chuàng)建了相同的對(duì)象,雖然創(chuàng)建車門時(shí)已經(jīng)創(chuàng)建了。

第二個(gè)問題是操作零件的類需要知道CompositePart和Part的詳細(xì)構(gòu)成,這點(diǎn)我們可以從求總價(jià)的計(jì)算中看出:

......
var totalPrice:Float {
        
        let total = parts.reduce(0){
            subtotal,part -> Float in
             return subtotal + part.price
        }
        
        
        return compositeParts.reduce(total){
            subtotal,cpart -> Float in
                return cpart.parts.reduce(subtotal){
                    tmptotal,tmpart -> Float in
                        return tmptotal + tmpart.price
                }
        }
    }
......

理解復(fù)合模式

復(fù)合模式通過樹型方式和定義允許獨(dú)立和復(fù)合對(duì)象一致的協(xié)議來解決上述問題。



實(shí)現(xiàn)復(fù)合模式

首先是定義協(xié)議,協(xié)議是復(fù)合模式的心臟。
(1) 樹角色(Component):代表復(fù)合對(duì)象和單個(gè)對(duì)象共有特征的抽象,該角色是一個(gè)抽象類,它有一個(gè)對(duì)象列表,定義了一些增刪對(duì)象的操作?! ?br> (2) 子樹角色(Composite):代表復(fù)合對(duì)象。樹上有很多子樹,子樹也是樹的一種?! ?br> (3) 樹葉角色(Leaf):獨(dú)立對(duì)象,也就是Component中的操作的單個(gè)對(duì)象。樹葉是只一個(gè)結(jié)點(diǎn)的樹,也是特殊的一種樹。

CarParts.swift

protocol CarPart {
    var name:String { get }
    var price:Float { get }
}

class Part : CarPart {
    let name:String
    let price:Float
        
    init(name:String, price:Float) {
        self.name = name
        self.price = price
    }
}

class CompositePart : CarPart {
    let name:String
    let parts:[CarPart]
    
    init(name:String, parts:CarPart...) {
        self.name = name
        self.parts = parts
    }
    
    var price:Float {
        return parts.reduce(0){
            total,part -> Float in
              return total + part.price
        }
   
    }
}

接著我們應(yīng)用復(fù)合模式:

Orders.swift

import Foundation
class CustomerOrder {
    let customer:String
    let parts:[CarPart]
    
    init(customer:String, parts:[CarPart]) {
        self.customer = customer
        self.parts = parts
    }
    
    var totalPrice:Float {
        return parts.reduce(0){
            total,part -> Float in
              return total + part.price
        }
   
    }
    
    func printDetails() {
        print("Order for \(customer): Cost: \(formatCurrencyString(totalPrice))");
    }
    
    func formatCurrencyString(number:Float) -> String {
        let formatter = NSNumberFormatter()
        formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
        return formatter.stringFromNumber(number) ?? ""
    }
}

最后,修改main.swift:

let doorWindow = CompositePart(name: "DoorWindow", parts:
    Part(name: "Window", price: 100.50),
    Part(name: "Window Switch", price: 12))

let door = CompositePart(name: "Door", parts:
    doorWindow,
    Part(name: "Door Loom", price: 80),
    Part(name: "Door Handles", price: 43.40))

let hood = Part(name: "Hood", price: 320)
let order = CustomerOrder(customer: "Bob", parts: [hood, door, doorWindow])

order.printDetails()

可以看出我們上面創(chuàng)建CompositePart時(shí)直接用了doorWindow對(duì)象。運(yùn)行程序,輸出一下內(nèi)容:

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

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,534評(píng)論 19 139
  • 設(shè)計(jì)模式匯總 一、基礎(chǔ)知識(shí) 1. 設(shè)計(jì)模式概述 定義:設(shè)計(jì)模式(Design Pattern)是一套被反復(fù)使用、多...
    MinoyJet閱讀 4,081評(píng)論 1 15
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,161評(píng)論 4 61
  • 《雞毛飛上天》是現(xiàn)在熱播的一部電視劇,陳江河就是劇中的雞毛,男一號(hào)。他從一開始倒騰襪子,到后來借著為襪廠救火...
    江上一扁舟閱讀 2,845評(píng)論 0 1
  • 前兩天下雨,基本沒出門,今兒看天氣不錯(cuò),出去溜達(dá)了一下,發(fā)現(xiàn)小區(qū)里的金絲桃長(zhǎng)得特別茂盛,綠葉之間已經(jīng)抽出了許...
    黯黯紅塵一路相伴閱讀 828評(píng)論 1 2

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