並非每一個自稱本身是個OO的人,他就必定能運用好OOP。
普通程序員寫的東西比如一把普通鑰匙,一把鑰匙只能開一個門,而高級程序員就會「造」萬能鑰匙。
我之前所理解的「簡單」就是一把鑰匙開一把鎖的模式,僅僅只是着眼於解決如今的問題,而設計模式的「複雜」在於它須要造出具備「通用性」的萬能鑰匙。而我之前寫的代碼就是前者,這個「簡單」不是功能的簡單,而是設計的簡單。簡單的設計意味着缺乏靈活性,代碼很鋼硬,僅僅只是面向過程,一步操做緊挨着下一步。
要使代碼可被反覆使用,請用’設計模式’對你的代碼進行設計.程序員
模擬鴨子程序開始了。
首先來一張類圖,這是鴨子程序原始狀態
算法
而此時咱們須要添加一個新功能:鴨子飛功能(吐槽:明明不少鴨子不會飛)
這很簡單,難不倒咱們「有OO思想」的人
編程
但這樣的設計運用在下面拓展的程序上會變成什麼呢?
設計模式
哇哦,很明顯橡皮鴨子不能飛,而在此設計中使用繼承(extends)就變得不合理了,
可是咱們能夠投機取巧一點,變成以下圖
ide
這樣小聰明的方法,恐怕我本身看的都不能直視了....
很明顯對於繼承在這個設計當中很幾個致命的地方
1:各個鴨子子類繼承父類時,使得代碼在多個子類中重複
2:沒有拓展性,對於改變會費勁
3:每每改變一點地方不少地方就都要跟着改變,找出其餘鴨子類中不想要的改變,牽一髮而動全身。學習
設計原則一:找出應用中可能須要變化之處,把它們獨立出來,不要和那些不須要變化的代碼混在一塊兒
注:當每次有新的需求的時候,就會使某方面發生變化,那麼你就能夠肯定,這部分的代碼就須要被抽出來,和其餘穩定的代碼有所區分,這樣使得代碼變化引發的不經意後果變少,系統變得更加富有彈性。
測試
設計原則二:針對接口編程,而不是針對實現編程。
注:從如今開始咱們編寫的代碼要富有彈性,讓其運行時能「動態」的改變飛行或者呱呱叫行爲this
進行一點小改變
這裏將飛行和叫的行爲各自「抽象」出來成接口,這兩個行爲被分開成兩個類,這兩個類專門爲提供某行爲的實現提供接口。不一樣與以前設計:行爲來自Duck父類中子類的具體實現,或是繼承某個接口並由子類自行實現而來。這兩種作法都依賴「實現」。而此時子類將使用接口所表明的行爲,因此實際的「實現」不會被綁死在鴨子的子類中。(特定的具體行爲編寫在實現了FlyBehavior和QuackBehavior接口的實現類中)spa
這裏放出具體行爲設計
注:此時飛行和叫的動做(接口)能夠被其餘對象複用,此時這兩個行爲和鴨子類(Duck)無關了,並且日後加入新的行爲也不怕了大量修改代碼了。設計
鴨子父類:
package Entity; import Interface.FlyBehavior; import Interface.QuackBehavior; //鴨子父類 public class Duck { // 添加兩個接口變量 FlyBehavior flyBehavior;// 每隻鴨子都會引用完成FlyBehavior接口的對象 QuackBehavior quackBehavior;// 每隻鴨子都會引用完成QuackBehavior接口的對象 public FlyBehavior getFlyBehavior() { return flyBehavior; } public void setFlyBehavior(FlyBehavior flyBehavior) { this.flyBehavior = flyBehavior; } public QuackBehavior getQuackBehavior() { return quackBehavior; } public void setQuackBehavior(QuackBehavior quackBehavior) { this.quackBehavior = quackBehavior; } public Duck() { } public void swim() { System.out.println("鴨子游泳。。。。。。"); } // 動做 public void display() { System.out.println("每隻鴨子都會動"); } // 這些方法取代fly(),quack() // 鴨子對象不親自處理呱呱呱叫行爲,而是委託給quackBehavior引用對象 public void performQuack() { quackBehavior.quack(); } // 鴨子對象不親自處理飛行爲,而是委託給flyBehavior引用對象 public void performFly() { flyBehavior.fly(); }; }
飛行和叫動做接口
package Interface; //飛行接口 public interface FlyBehavior { public void fly(); }
package Interface; //鴨子叫接口 public interface QuackBehavior { public void quack(); }
//綠頭鴨和橡皮鴨類
package Entity; import Implements.FlyWithWings; import Implements.Quack; //綠頭鴨子類 public class MallardDuck extends Duck { @Override public void display() { System.out.println("綠頭鴨子"); } /* 當MallardDuck被實例化時, * 構造器會把繼承來的quackBehavior,flyBehavior * 實例變量初始化成Quack,FlyWithWings的類型 * Quack,FlyWithWings分別是接口的實現類 * */ public MallardDuck() { quackBehavior = new Quack(); flyBehavior = new FlyWithWings(); } }
package Entity; import Implements.FlyNoWay; import Implements.Squeak; public class RubberDuck extends Duck { //橡皮鴨類 @Override public void display() { System.out.println("我是一隻橡皮鴨"); } public RubberDuck() { quackBehavior = new Squeak(); flyBehavior = new FlyNoWay(); } }
各個行爲的具體實現類,都實現了接口
package Implements; import Interface.FlyBehavior; public class FlyNoWay implements FlyBehavior { @Override public void fly() { System.out.println("不會飛"); } }
package Implements; import Interface.FlyBehavior; public class FlyWithWings implements FlyBehavior { @Override public void fly() { System.out.println("鴨子飛起來了。。。。。。"); } }
package Implements; import Interface.QuackBehavior; public class MuteQuack implements QuackBehavior { @Override public void quack() { System.out.println("不會叫"); } }
package Implements; import Interface.QuackBehavior; public class Quack implements QuackBehavior { @Override public void quack() { System.out.println("鴨子呱呱呱叫。。。。。。"); } }
package Implements; import Interface.QuackBehavior; public class Squeak implements QuackBehavior { @Override public void quack() { System.out.println("鴨子吱吱吱叫。。。。。。"); } }
測試類
package TestMain; import Entity.Duck; import Entity.MallardDuck; import Entity.RubberDuck; public class TestMain { public static void main(String[] args) { //這裏使用多態,讓Duck知道咱們要建立一隻綠頭鴨 Duck d = new MallardDuck(); //重載方法 d.display(); d.performQuack(); d.performFly(); System.out.print("\n"); Duck a=new RubberDuck(); a.display(); a.performQuack(); a.performFly(); } }
效果:
設計原則三:多用組合,少用繼承。
注:使用組合創建系統具備很大的彈性,不只可將算法封裝成類,更能夠「動態的改變行爲」,只要組合對象符合正確的接口標準便可。
此時我剛剛寫的例子基於一個策略模式思想寫的。固然你可能會問:「用這個設計模式到底有什麼用呢?這樣功能我也能實現了,幹嗎要搞的那麼複雜?」。對此我不能用專業的思想去回答這樣的疑問,我只能說隨着本身學習的不斷深刻每每不少之前自認爲對的東西,實際上是不正確的。
策略模式要點:
1:良好的OO設計必須具有可複用性、可擴充性、可維護性三個特徵
2:模式不是代碼,而是針對設計問題的通用解決方案。
3:大多數的模式都容許系統局部改變獨立於其餘部分。
4:記着把系統中會改變的部分抽出來封裝
5:模式會讓開發人員之間有共同的語言,並且會讓本身少走不少坑
這裏我想說一點,不少人都以爲設計模式跟算法同樣都是無關緊要的東西,我以爲用設計模式是着眼於將來,能夠提升系統的擴展性,減小重複勞動,雖然有的時候可能會增長工做量,但比起後期無止境的維護,這點反而不算什麼,而設計模式是不會提升系統運行速度的,但我認爲設計模式很是重要,包括帶個人前輩程序員都教導我腦中要有模式概念,固然這個要因人而異。
感謝你看到這裏,策略模式部分結束,本人文筆隨便,如有不足或錯誤之處望給予指點,90度彎腰~很快我會發佈下一個設計模式內容,生命不息,編程不止!
參考書籍:《Head First 設計模式》