還記得上次介紹「觀察者設計模式」提到的Wood Bakery嗎?這次我們來看看他們的內部系統。
Wood Bakery除了每天會宣布一個Today’s Special以外,他們還有一個特色,每當有人下單,就會有一個人負責喊「10份草莓大福」之類的。
所以這個系統的基本功能:
- 設定店名
- 顯示今日特色
- 喊出客人所點的東西
Wood Bakery Code,其中我們用一個Struct來定義WoodSpecial。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
struct WoodSpecial { var name:String var price:Float var amount:Int } class WoodBakery { var name:String init(name:String) { self.name = name } func showTodaySpecial() { print("\(name) 今日特色:") let items = getTodaySpecial() for item in items { print("\(item.name), 價格 \(item.price), 數量 \(item.amount)") } } func orderItem(name:String,amount:Int) { print("有客人下單:\(amount) 份 \(name)") } private func getTodaySpecial() -> [WoodSpecial] { var items = [WoodSpecial]() items.append(WoodSpecial(name: "法國麵包", price: 180, amount: 20)) items.append(WoodSpecial(name: "蒜蓉麵包", price: 70, amount: 15)) items.append(WoodSpecial(name: "太陽餅", price: 85, amount: 10)) items.append(WoodSpecial(name: "草莓大福", price: 400, amount: 5)) return items } } |
讓我們在main中執行看看
1 2 3 4 5 6 7 8 |
let woodBakery = WoodBakery(name: "Wood 1號店") woodBakery.showTodaySpecial() print("-----------------------") woodBakery.orderItem(name: "法國麵包", amount: 5) woodBakery.orderItem(name: "太陽餅", amount: 75) woodBakery.orderItem(name: "草莓大福", amount: 100) |
輸出結果:
1 2 3 4 5 6 7 8 9 |
Wood 1號店 今日特色: 法國麵包, 價格 180.0, 數量 20 蒜蓉麵包, 價格 70.0, 數量 15 太陽餅, 價格 85.0, 數量 10 草莓大福, 價格 400.0, 數量 5 ----------------------- 有客人下單:5 份 法國麵包 有客人下單:75 份 太陽餅 有客人下單:100 份 草莓大福 |
目前來看就是把所有的功能都寫在了WoodBakery這個Class中。
但隨著Wood Bakery的系統越來越智能,他們提供的功能也開始變多了,這時候如果繼續把所有的功能寫在一起,似乎會讓這個Class越來越臃腫,能不能將部分的功能交給別人來做呢?
代理模式(Proxy Pattern)
代理模式的核心是一個代理對象,此對象可以用語代表其他資源。
代理模式的使用場景:
- 定義一個面向網頁或者RESTful服務等遠程資源的接口。
- 管理開銷比較大的操作的執行過程。
- 為其他對象的屬性和方法加上訪問控制。
我們為Stone Bakery設計的系統:
首先我們為了將『準備Today’s Special」以及「喊單」的工作交給別人,我們定義了StoneBakeryDataSource以及StoneBakeryDelegate兩個Protocol。
1 2 3 4 5 6 7 |
protocol StoneBakeryDataSource { func todaySpecial() -> [StoneSpecial] } protocol StoneBakeryDelegate { func didOrderItem(name:String, amount:Int) } |
- 當有人要接手「準備Today’s Special」的工作時,他必須實現StoneBakeryDataSource中所提到的方法。
- 當有人要接手「喊單」的工作時,他必須實現StoneBakeryDelegate中所提到的方法。
1 2 |
var dataSource:StoneBakeryDataSource? var delegate:StoneBakeryDelegate? |
我們決定將「準備Today’s Special」的工作交給Chief
1 2 3 4 5 6 7 8 9 10 11 |
class StoneChef:StoneBakeryDataSource { func todaySpecial() -> [StoneSpecial] { var items = [StoneSpecial]() items.append(StoneSpecial(name: "法國麵包", price: 180, amount: 20)) items.append(StoneSpecial(name: "蒜蓉麵包", price: 70, amount: 15)) items.append(StoneSpecial(name: "太陽餅", price: 85, amount: 10)) items.append(StoneSpecial(name: "草莓大福", price: 400, amount: 5)) return items } } |
我們將「喊單」的工作交給Waiter
1 2 3 4 5 |
class StoneWaiter:StoneBakeryDelegate { func didOrderItem(name: String, amount: Int) { print("客人下單:\(amount) 份 \(name)") } } |
在初始化時,我們實例化StoneChef和StoneWaiter並且將他們分別賦值給dataSource、delegate。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
class StoneBakery { var name:String var dataSource:StoneBakeryDataSource? var delegate:StoneBakeryDelegate? init(name:String) { self.name = name let chef = StoneChef() dataSource = chef let waiter = StoneWaiter() delegate = waiter } func showTodaySpecial() { print("\(name) 今日特色:") let items = dataSource?.todaySpecial() if items == nil { print("廚師不在") return } for item in items! { print("\(item.name), 價格 \(item.price), 數量 \(item.amount)") } } func orderItem(name:String,amount:Int) { delegate?.didOrderItem(name: name, amount: amount) } } |
實際上在Main調用方法時,是這樣的:
1 2 3 4 5 6 7 8 |
let stoneBakery = StoneBakery(name: "Stone 1號店") stoneBakery.showTodaySpecial() print("-----------------------") stoneBakery.orderItem(name: "法國麵包", amount: 10) stoneBakery.orderItem(name: "太陽餅", amount: 120) stoneBakery.orderItem(name: "草莓大福", amount: 330) |
輸出結果:
1 2 3 4 5 6 7 8 9 |
Stone 1號店 今日特色: 法國麵包, 價格 180.0, 數量 20 蒜蓉麵包, 價格 70.0, 數量 15 太陽餅, 價格 85.0, 數量 10 草莓大福, 價格 400.0, 數量 5 ----------------------- 客人下單:10 份 法國麵包 客人下單:120 份 太陽餅 客人下單:330 份 草莓大福 |
在我們把工作都交給別人之後真的輕鬆很多啊~這裡將代理模式的例子放在github上面提供參考。