Design Pattern
類別圖:符號
在 Head First 書中看到較多使用,結合(association)、繼承,沒有依賴
在 Head First 書中看到較多使用,結合(association)、繼承,沒有依賴
- 單向結合
- 起始方 會 吃(使用) 箭頭方的物件,並加以使用
- 快記: 吃他 (他指箭頭指向位置)
- 繼承
- 箭頭方--為父類別(介面)
- 快記: 繼承他, 實作他 (他指箭頭指向位置)
模式介紹
Strategy 策略模式
- 目的: 切開 客戶 與 演算法(行為)
- 定義: 封裝演算法家族,讓演算法變動時,不影響使用該演算法的程式
- 演算法(行為),可以在 Client 物件建立後,才動態加入或隨意更換
- 作法:
- 建立 abstruct class 給客戶端繼承
- 建立行為接口
- 建立動態指定行為物件的接口、屬性
- 客戶端(ex. RedheadDuck)實作,直接對行為屬性操作,如: flyB.fly()
- 建立行為介面,並實作
- 客戶端隨時可透過 setAtkBehavior() 更換行為物件
Observer 觀察者模式
- 目的: 通知 有註冊的觀察者
- 定義: 定義了物件之間 1:N 關係,當其一個物件改變狀態,其他都能收到通知並更新。
- java.util 有 Observer 介面 & Observable 類別可直接使用
- 作法:
- 主題物件必須實作 註冊、移除、通知觀察者
- 觀察者,需實作 被通知後的更新
- 每個主題可有 N 個觀察者
- 每個觀察者必須先跟主題 註冊 才能開始觀察
Decorator 裝飾模式
- 目的: 不改變介面,但加入責任
- 定義: 動態的將責任加在物件身上,裝飾者比繼承提供更有彈性的擴充功能
- 雞包蛋是雞,紙包雞是紙
- 作法:
- Component(drink) & Decorator 是抽象類別
- Mocha & Latte 是基礎類別,實作 drink
- 從 decorator 實踐一個 ConcreteDecoratorA 物件
- 保存上一個(super) drink 物件
- 實作 cost(), desc()...功能,直接操作 保存的 drink 物件
- Decorator 抽象類別可以自行加上新的方法
- 假設實踐了一個 裝飾者A 叫做 milk,
使用方式 new milk(new Mocha).cost()
Simple Factory 簡單工廠 (算Coding習慣,非模式)
- 目的: 減少 new 物件帶來的相依性
- 定義: 封裝N個建立物件的程式碼,統一出口
- 產生物件的類別,稱作工廠,工廠會生很多物件出來
- 作法:
- 將 N 個會產生相似 物件的 create 程式碼拉成新 Class, SimplePizzaFactory,稱作工廠
- SimplePizzaFactory 會 依照type 來 return Pizza 物件
- 主程式 Store 直接將需求的 type 參數給 工廠,直接產生 Pizza 物件並操作
- 用法:
- SimplePizzaFactory.createPizza(cheese);
Factory Method 工廠方法模式
- 定義: 讓次類別決定要實體化的類別為何
- 由工廠方法決定產生的物件
- 抽象類別 abstract Product factoryMethod(type);
- 次類別 需實作方法 Product factoryMethod(type){if(xxx) return Product;}
- 與簡單工廠、抽象工廠的差別
- Simple Factory 1個 creator
- Factory Method N個 creator,1個抽象產品類別
- abstact Factory N個 creator,N個抽象產品類別
- 作法:
- 呈 上例
- 很多個 Store 產生了很多 Factory,若要統一管理,又變成 if else 判斷用哪個 Factory
- 改變 create 物件的方式,改由 Store 自己的工廠去實踐
- 每個 PizzaStore 都必須實踐工廠方法 createPizza(type)
- orderPizza() 再去呼叫 createPizza() 方法來操作
- 用法:
- NYStore.factoryMethod(cheese);
- Creator 可以決定 由哪個 Product 執行 (在 factoryMethod() 中仍需用 if else 判斷)
- 每增加一個 Product,Creator 就增加一個相依的對象
- 守則"依賴抽象類別,不依賴具象",因此產生一個 Creator 的抽象類別
- 示意
- createPizza() 為 工廠方法,傳入 type 之後,會從 Pizza 物件中挑出指定 Product 回傳
Abstract Factory 抽象工廠模式
- 定義: 提供一個介面,建立相關or相依物件之家族,而不需明確指定具象類別
- 相較於 factory Method,會將明確的具象類別寫在 createPizza() 中,
abstract Factory 則是由 Client 端 給予 - 角色: Factory(工廠)、Product(產品)、Client(客戶端)
- 工廠可以創建 N 個不同 類型 的Product
- 工廠方法vs抽象工廠
- 工廠方法常和抽象工廠一起使用
- factory method針對的是一個產品等級結構
- abstract factory是多個產品等級結構的
- 區別:
- factory method 只有一個抽象產品類,而抽象工廠模式有多個。
- factory method 的具體工廠類只能創建一個具體產品類的實例,而抽象工廠模式可以創多個
- 作法:
- 建立抽象產品(ex. cheese),並實作
- 建立抽象工廠,實作 CreateProduct(),回傳 Product 實體(由 Factory 自己決定)
- Client 實作 CreatePizza()
- 可使用 NY 或 Chicago Factory
- cheese = factory.CreateCheese()
- 其中所包含的 Product 將會有所不同
Singleton 獨體模式
- 目的: 只允許存在一個實體
- 定義: 確保一個類別只有一個實體,並給他一個存取的全域點(global point)
- 注意,多執行續必須另外處理(兩種方式)
- 在屬性宣告後,優先實體化。缺點是沒用到也會建立他
- 雙重檢查上鎖
- 在屬性加上 volatile
- getInstance() 加上檢查 null & syncronized(Singleton.class)
- 作法:
- 利用封閉屬性儲存自己
- 所有使用此物件都必須從 getInstance() 取得實體
- ex. Calendar.getInstance()
Command 命令模式
- 目的: 封裝請求 (把調用方法封裝起來)
- 定義: 將 請求 封裝成物件,以便使用不同的請求,參數化其他物件。也支援命令復原。
- 角色:
- Invoker 發布命令物件 (吃 command)
- command 命令物件 (吃 recevier)
- Recevier 被控制的物件(接收者)
- 操作:
- 在 client,產生 command 物件
- 在 client,將 command 丟到 invoker 中 (可以是N個)
- Run invoker (有點像是跑排程,會照順序執行)
- 作法:
- 建立 ConcreteCommand,吃 Recevier 物件,並在 execute 中實作
- 建立 Invoker
- 允許吃 Command 物件,並存在屬性中
- 可以依照順序將 Command 一個個 execute
- 建立 Client
- 產生 Recevier,放入 ConcreteCommand
- 產生 Invoker,將 ConcreteCommand 放入 Invoker
- 執行 Invoker
Adapter 轉接器
- 目的: 將一個介面 轉成 另一個介面
- 定義: 將介面轉成另一個介面,讓原本不相容的類別可以合作
- 讓鴨子看起來像鵝
- Client 只吃 鵝(介面)
- 建立一個 adapter 並繼承 鵝介面
- 讓 adapter 能吃 鴨子(介面)
- 用鴨子去實踐 鵝介面中的 function
Facade 表象模式
Template method 樣板方法模式
- 目標: 定義演算法大綱,讓次類別可變更某些細節
- 定義: 演算法定義在方法中,演算法中的某些方法可以定義在次類別中,讓次類別在不影響演算法的情況下,重新定義演算法中的某些步驟。
- 作法:
- 建立一個 abstruct Class
- templateMethod() 放演算法
- primitive opration() 提供給次類別實作(必要)
- concreteOperation() 為自身擁有的 method,可給自己 or 次類別使用
- hook() 掛勾,為次類別有需要才實作(非必要)
- 操作
- 產生ConreteClass 在執行 templateMethod()
Iterator 反覆器
- 目的: Loop 取得元素
- 定義: 讓我們取得 聚集 中的每個元素,而不須暴露實踐方式
- 作法:
- 實作一個 concreteIterator
- 針對傳入的聚集(items清單),來實作相關method
- 實作一個 concrete聚集
- 在 createIterator() 中,將產生的 concreteIterator 回傳
- 使用:
- Client 呼叫 concrete聚集.createIterator() 取得反覆器
- 利用反覆器取得單一個元素
Composite 合成模式
- 目的: 樹狀結構
- 定義: 讓你的物件能合成數狀結構,呈現"部分/整體"階層關係。但仍可用一至的方式處理個別&合成物件。
- 角色:
- 元件 -- 擁有葉子 & 合成物件 所有實作的method
- 合成物件 -- 需實作 add & remove 等方法,讓物件能夠產生階層關係
- 葉子 -- 沒有子物件
- 作法:
- 建立 Component 抽象物件
- 將葉子、合成物件需要的方法開好
- 在每個必要實踐的方法中,塞入 error Exception
- 建立葉子,因為沒有子物件,只需實踐基本功能
- createIterator() 可以建立一個 NullIterator 並回傳
- 建立 Composite 物件
- 同樣實踐 add & remove 等階層相關的功能
- 在屬性存放 子Component 清單
- createIterator() 回傳 合成反覆器
- 建立 CompositeIterator 物件(不需要則可忽略)
- 實踐 Iterator 介面
- 如要做倒敘的反覆器,使用 Stack 儲存(後進先出)
- 實作 next(),有下一個,就 createIterator() 並放入 Stack
- 實作 hasNext(),有下一個回傳 true,沒有就清掉該反覆器
- 使用:
- 只需要操作葉子 & 合成物件,相當於 葉子 & 節點
- 產生 N子物件(兩者不限)
- 產生 合成物件,將 N子物件 add 放入
- 由底層一層一層加上去
State 狀態模式
- 目的: 封裝 狀態的行為,依狀態改變行為
- 定義: 允許物件隨著內在狀態改變而變更行為,好像物件類別改變了一樣
- 如果 Context 物件消失,State 將會回到初始
- 作法:
- 建立 State 抽象物件,並將所有動作寫成N個方法
- 一個狀態就建立一個 concreteState 物件
- 吃 Context ,方便呼叫 setState 等方法
- handle() 中做完行為,使用 setState(Context.getConcretStatA()) 去變更狀態物件
- 當再次執行,會去呼叫儲存在屬性的 State物件中的該動作
- 使用:
- 建立一個 Context 並保持活著
- loop 執行 request()
proxy 代理人模式
- 目的: 將物件包裝起來,進行存取控制
- 定義: 讓某個物件擁有替身,藉以控制外界對此物件的接觸
- 應用範圍舉例
- Cache Proxy 備用代理:會記住之前 request 的資料,並盡量重複利用
- Remote Proxy 遠端代理:代理遠端程式執行,如Web Service和WCF、java RMI。
- Virtual Proxy 虛擬代理:將複雜或耗時實體利用物件替代
- Protection Proxy 安全代理:控制物件存取權限。ex.CGlib
- Smart Proxy 智慧參考:提供比原始物件更多服務。
- 作法:
- 依照 RealSubject 架構建立一個 interface
- 並讓 Proxy 物件實作,讓別人誤以為 Proxy 就是 RealSubject
- 在 Proxy 物件提供 request,必要的時候才會將 request 給 RealSubject 去處理
- 保護代理人作法:(參考文獻)
- 使用 java.lang.reflection 中的 InvocationHandler(調用處理器) 介面 & Proxy 物件
- IH(InvocationHandler 縮寫) 能讓 Proxy & RealSubject 之間有多一層控管機制
- 可能有N個不同權限的 IH
- 原本 invoke 是直接寫在 Proxy 物件中有所不同,java proxy 不允許修改,故將其切割成兩塊,IH 另外實作。
- 作法:
- 實踐 IH
- 能夠儲存 RealSubject 物件
- invoke() ,直接對存放在屬性的 RealSubject 物件做調用
- 權限的控管也是寫在此方法內
- 吃 RealSubject 物件的方法,回傳 Proxy 物件(Subject介面被套上)
- Proxy.newProxyInstance(Subject物件Loader, Subject物件介面, 包含了 RealSubject 的 IH )
- 使用:
- 將 RealSubject物件 、IH 物件 丟給 Proxy.newProxyInstance 產生一個擁有 Subject 介面的代理人物件
- 將回傳的 物件轉型回 RealSubject
- 即可依照一般方式使用 RealSubject.request()
Compound 複合模式
剩下的模式
- Bridge 橋梁模式
- Builder 建立者模式
- Chain of Responsibility 責任鏈模式
- Flyweight 蠅量級模式
- Interpreter 翻譯者模式
- Mediator 居間協調者模式
- Memento 助記物模式
- Prototype 雛形模式
- visitor 參觀者模式
模式分類
- 生成
- 結構
- 行為
- 類別
- 物件
OO守則
- 將變動部分封裝起來
- 多用合成、少用繼承
- 針對介面寫程式,不是對實踐寫程式
- 意思是對超型態而寫,超型態可以是: 抽象類別、介面
- 鬆綁物件間的緊密度
- 類別開放擴充、關閉修改
- 依賴抽象,不依賴具象類別
- 將原本依賴的具象類別,衍伸出一個抽象類別給予次類別依賴
- 只告訴你的朋友
- 別找我,我會找你
- 類別只有一個理由可改變
參考書籍
Design Pattern
Reviewed by Wild
on
5/13/2014 10:01:00 上午
Rating:
沒有留言:
沒有Google帳號也可發表意見唷!