【正文】
O t h e r D u c k綠頭鴨子 紅頭鴨子 3 需求變了 ?新需求 ? 希望模擬的鴨子會飛 ? 初步的解決方案:在 Duck中增加 fly()方法, 所有鴨子就會飛了 D u c k+ q u a c k ( )+ s w im ( )+ f ly ( )+ d is p la y ( )M al l ar d D u c k+ d is p la y ( )R e d h e ad D u c k+ d is p la y ( )O t h e r D u c k4 橡皮鴨飛起來了! ?問題來了 ? 基類中的 fly()方法導(dǎo)致所有子類均繼承給方法,但并不是所有的子類都需要 fly()方法; ? 為了復(fù)用( reuse)而使用繼承,往往存在問題! D u c k+ q u a c k ( )+ s w im ( )+ f ly ( )+ d is p la y ( )M al l ar d D u c k+ d is p la y ( )R e d h e ad D u c k+ d is p la y ( )R u b b e r D u c k+ q u a c k ( )+ d is p la y ( )覆蓋了橡皮鴨的叫聲 5 覆蓋橡皮鴨中的 fly ?勉強的解決方案 ? 在橡皮鴨中覆蓋 fly()方法 ? Fly() { //什么也不干 } ? 如果加入誘餌鴨,不會飛也不會叫,如何? D u c k+ q u a c k ( )+ s w im ( )+ f ly ( )+ d is p la y ( )M al l ar d D u c k+ d is p la y ( )R e d h e ad D u c k+ d is p la y ( )R u b b e r D u c k+ q u a c k ( )+ f ly ( )+ d is p la y ( )6 提煉接口 ?繼承可能不是答案 ? 需要經(jīng)常添加不同的鴨子產(chǎn)品,都要檢查并覆蓋方法 ? 新的解決方案:定義接口 7 評價方案 ?接口的問題 ? 隨著 Duck的子類越來越多,每種鴨子都要實現(xiàn)相應(yīng)的接口,重復(fù)代碼越來越多,代碼無法復(fù)用 8 軟件開發(fā)的不變真理 ?不管你在何處工作,構(gòu)建什么,用什么語言編程,伴隨軟件開發(fā)的不變真理 ?Change ?不管軟件當初設(shè)計的多么好,一段時間乊后,總是需要成長與改變。 9 問題分析 ?問題 ? 鴨子的行為在子類中不斷變化,繼承難以解決該問題,讓所有子類繼承這些行為是不恰當?shù)? ? Flyable和 Quackable接口,想法不錯,但 Java接口沒有實現(xiàn)代碼,造成代碼無法復(fù)用,代碼在子類中重復(fù) ? 設(shè)計原則 ? 找出應(yīng)用中可能需要變化的地方,把它們獨立出來并“封裝”起來,不要和哪些不需要變化的代碼混合在一起 ? 變化的部分取出并封裝后,便于以后的改動或擴充,而不影響其它部分 ? 變化的東西: 鴨子的行為 10 提取并封裝類 ?將 Duck類中 fly和 quack方法提取出來 ? 它們是子類中的易于變化的部分 ? 定義 fly相關(guān)的類,封裝鴨子的 fly行為 ? 定義 quack相關(guān)的類,封裝鴨子的 quack行為 ?初步設(shè)想 ? 在獨立的類中定義鴨子的行為; ? 在 Duck中包含“指定”的行為,甚至可以在運行時動態(tài)改變行為 11 鴨子行為類的設(shè)計 ?設(shè)計原則 ? 針對接口編程,而不是針對實現(xiàn)編程 ?定義行為接口及其實現(xiàn) ? FlyBehavior和 QuackBehavior接口,定義具體的行為類實現(xiàn)該接口 ? Duck類依賴行為接口,不關(guān)心行為的具體實現(xiàn) ? 原來做法的問題:行為或者在 Duck類中實現(xiàn),或者繼承某個接口而在子類中實現(xiàn),依賴實現(xiàn)細節(jié)。 ... public void performQuack(){ ()。 flyBehavior = new FlyWithWings()。 } public void setQuackBehavior(QuackBehavior qb){ quackBehavior=qb。 public void fly()。 public void fly()。 public TurkeyAdapter(Turkey t){ =t。 } } 23 類結(jié)構(gòu) 24 冒充吧-測試代碼 public class TestDriver{ public static void main(String[] args) { WildTurkey turkey = new WildTurkey()。 testDuck(turkeyAdapter)。 ()。 if(piic) duck = new MallardDuck()。 .... 28 問題分析 ?針對接口編程的好處 ? 可以隔離以后系統(tǒng)可能發(fā)生的變化 ? 如果針對接口編程,借助多態(tài),系統(tǒng)可以適應(yīng)任何實現(xiàn)接口的新類 ? 代碼使用大量的具體類時,系統(tǒng)非常僵硬,一旦需要加入新類,必須修改代碼 ?直接使用具體類時違背的原則 ? 對擴展開發(fā),對修改關(guān)閉 ? 解決策略:找出系統(tǒng)中變化的部分,從不變部分分離 29 匹薩店制作匹薩 ?訂購匹薩 P iz z a+ p r e p a r e ( )+ b a k e ( )+ c u t( )+ b o x ( )Pizza orderPizza(){ Pizza pizza = new Pizza()。 ()。 ()。 } 希望 Pizza為抽象類或接口 30 需要更多的匹薩類型 Pizza orderPizza(String type){