一、引言 設計模式是軟體開發人員在軟體開發過程中面臨的一般問題的解決方案。這些解決方案是眾多軟體開發人員經過相當長的一段時間的試驗和錯誤總結出來的。學習設計模式會幫助你更好的理解面向對象。 設計模式有多達23種,這些模式可以分為三大類:創建型模式(Creational Patterns)、結構型模式 ...
一、引言
設計模式是軟體開發人員在軟體開發過程中面臨的一般問題的解決方案。這些解決方案是眾多軟體開發人員經過相當長的一段時間的試驗和錯誤總結出來的。學習設計模式會幫助你更好的理解面向對象。
設計模式有多達23種,這些模式可以分為三大類:創建型模式(Creational Patterns)、結構型模式(Structural Patterns)、行為型模式(Behavioral Patterns)
學習設計模式主要是通過《Head First 設計模式》,並參照了一些其他教程。學習心得記錄於此,幫助自己深入理解。
開始第一個設計模式前,先看下設計模式的六大原則(之前面試曾被問過)
1、開閉原則(Open Close Principle)
開閉原則的意思是:對擴展開放,對修改關閉。在程式需要進行拓展的時候,不能去修改原有的代碼,實現一個熱插拔的效果。簡言之,是為了使程式的擴展性好,易於維護和升級。想要達到這樣的效果,我們需要使用介面和抽象類,後面的具體設計中我們會提到這點。
2、里氏代換原則(Liskov Substitution Principle)
里氏代換原則是面向對象設計的基本原則之一。 里氏代換原則中說,任何基類可以出現的地方,子類一定可以出現。LSP 是繼承復用的基石,只有當派生類可以替換掉基類,且軟體單位的功能不受到影響時,基類才能真正被覆用,而派生類也能夠在基類的基礎上增加新的行為。里氏代換原則是對開閉原則的補充。實現開閉原則的關鍵步驟就是抽象化,而基類與子類的繼承關係就是抽象化的具體實現,所以里氏代換原則是對實現抽象化的具體步驟的規範。
3、依賴倒轉原則(Dependence Inversion Principle)
這個原則是開閉原則的基礎,具體內容:針對介面編程,依賴於抽象而不依賴於具體。
4、介面隔離原則(Interface Segregation Principle)
這個原則的意思是:使用多個隔離的介面,比使用單個介面要好。它還有另外一個意思是:降低類之間的耦合度。由此可見,其實設計模式就是從大型軟體架構出發、便於升級和維護的軟體設計思想,它強調降低依賴,降低耦合。
5、迪米特法則,又稱最少知道原則(Demeter Principle)
最少知道原則是指:一個實體應當儘量少地與其他實體之間發生相互作用,使得系統功能模塊相對獨立。
6、合成復用原則(Composite Reuse Principle)
合成復用原則是指:儘量使用合成/聚合的方式,而不是使用繼承。
這些原則要多學習,多體驗才能更深的理解
二、策略模式
定義:定義了演算法族,分別封裝起來,讓它們之間可以互相替換,此模式讓演算法的變化獨立於使用演算法的客戶。
意圖:定義一系列的演算法,把它們一個個封裝起來, 並且使它們可相互替換。
主要解決:在有多種演算法相似的情況下,使用 if...else 所帶來的複雜和難以維護。
何時使用:一個系統有許多許多類,而區分它們的只是他們直接的行為。
如何解決:將這些演算法封裝成一個一個的類,任意地替換。
關鍵代碼:實現同一個介面。
三、實現
實例剖析:基類鴨子,鴨子有飛行及喊叫的行為,飛行和喊叫都可以分別封裝成一個演算法族,將演算法介面放入鴨子基類中,那麼在鴨子子類中可以自由選擇行為。如果有新的飛行或者喊叫方式,則只需要增加一個飛行策略類繼承飛行介面即可。
1.類圖設計
2.具體實現
java代碼實現
鴨子基類
public abstract class Duck { //飛行介面 Flybehavior flybehavior; //叫聲介面 QuackBehavior quackBehavior; public Duck(){ } //叫聲方法 public void performquack(){ quackBehavior.quack(); } //飛行方法 public void performFly(){ flybehavior.fly(); } public abstract void display(); public void swim() { System.out.println("All ducks float, even decoys!"); } }View Code
飛行介面及相關策略子類
//飛行介面 public interface Flybehavior { void fly(); } //具體飛行演算法(不會飛) public class FlyNoWay implements Flybehavior { public void fly() { System.out.println("I can’t fly"); } } //可以飛 public class FlyWithWings implements Flybehavior { public void fly() { System.out.println("I’m flying!!"); } }View Code
喊叫介面及相關策略子類
//喊叫介面 public interface QuackBehavior { void quack(); } //喊叫策略演算法類 public class Quack implements QuackBehavior { public void quack() { System.out.println("Quack"); } } public class MuteQuack implements QuackBehavior { public void quack() { System.out.println("<< Silence >>"); } } public class Squeak implements QuackBehavior { public void quack() { System.out.println("Squeak"); } }View Code
鴨子類
//鴨子子類 public class MallardDuck extends Duck { public MallardDuck(){ quackBehavior=new Quack(); flybehavior=new FlyWithWings(); } public void display() { System.out.println("I’m a real Mallard duck"); } }View Code
運行
public static void main(String[] args) { Duck mallardDuck=new MallardDuck(); mallardDuck.performFly(); mallardDuck.performquack(); }View Code
運行結果
四、策略模式的優缺點:
優點: 1、策略類之間可以自由切換。由於策略類都實現同一個介面,所以使它們之間可以自由切換。 2、避免使用多重條件判斷。 3、擴展性良好。有新的演算法時,只需要新增一個策略類即可,不需要修改原有代碼
缺點: 1、策略類會增多。 2、所有策略類都需要對外暴露。
使用場景: 1、如果在一個系統裡面有許多類,它們之間的區別僅在於它們的行為,那麼使用策略模式可以動態地讓一個對象在許多行為中選擇一種行為。 2、一個系統需要動態地在幾種演算法中選擇一種。 3、如果一個對象有很多的行為,如果不用恰當的模式,這些行為就只好使用多重的條件選擇語句來實現。
註意事項:如果一個系統的策略多於四個,就需要考慮使用混合模式,解決策略類膨脹的問題。