定義一系列算法,分別封裝起來,讓它們之間能夠呼死去那個替換,此模式讓算法變化,不會影響到使用算法的客戶java
示例來自於Head First上的鴨子例子,一個鴨子的系統,系統中會出現不一樣的鴨子,一邊游泳一邊叫。綠頭鴨子會飛,會游泳,正常呱呱叫,橡皮鴨子不會飛不會游泳吱吱叫。後期可能會擴展其餘的鴨子好比紅頭鴨子或者誘餌鴨。鴨子系統的設計類圖以下
算法
首先建立鴨子類編程
/** * 鴨子抽象類 * * @author Colin * @create 2018-02-25 **/ public abstract class Duck { private FlyBehavior flyBehavior; private QuackBehavior quackBehavior; public Duck(){} /** * 外觀顯示方法 */ public abstract void display(); public void swim(){ System.out.println("咱們都是鴨子,咱們都會游泳!"); } /** * 飛行 */ public void performFly(){ flyBehavior.fly(); } /** * 叫 */ public void performQuack(){ quackBehavior.quack(); } public void setFlyBehavior(FlyBehavior flyBehavior) { this.flyBehavior = flyBehavior; } public void setQuackBehavior(QuackBehavior quackBehavior) { this.quackBehavior = quackBehavior; } }
鴨子具體實現類ide
/** * 綠頭鴨子 * * @author Colin * @create 2018-02-25 **/ public class MallardDuck extends Duck{ @Override public void display() { System.out.println("我是綠頭鴨子!"); } }
/** * 橡皮鴨子 * * @author Colin * @create 2018-02-26 **/ public class RebberDuck extends Duck { @Override public void display() { System.out.println("我是橡皮鴨子!"); } }
建立鴨子飛行和叫的接口和實現類,不一樣的鴨子叫聲或者是飛行的方式不同,因此相對於整個系統來講這塊是可變的,單獨提取封裝起來。測試
/** * 飛行行爲 * * @author Colin * @create 2018-02-25 **/ public interface FlyBehavior { public void fly(); } /** * 叫的行爲 * * @author Colin * @create 2018-02-25 **/ public interface QuackBehavior { public void quack(); }
/** * 不會飛行 * * @author Colin * @create 2018-02-25 **/ public class FlyNoWay implements FlyBehavior { @Override public void fly() { System.out.println("我不會飛!"); } } /** * 飛行具體實現類 * * @author Colin * @create 2018-02-25 **/ public class FlyWithWings implements FlyBehavior { @Override public void fly() { System.out.println("我會飛!"); } }
/** * 呱呱叫 * * @author Colin * @create 2018-02-25 **/ public class Quack implements QuackBehavior { @Override public void quack() { System.out.println("正常鴨子呱呱叫!"); } } /** * 吱吱叫 * * @author Colin * @create 2018-02-25 **/ public class Squack implements QuackBehavior { @Override public void quack() { System.out.println("橡皮鴨子吱吱叫!"); } }
測試類this
/** * 鴨子測試類 * * @author Colin * @create 2018-02-25 **/ public class DuckTest { @Test public void testMallardDuck(){ // 綠頭鴨子會呱呱叫,會飛 Duck duck=new MallardDuck(); duck.setFlyBehavior(new FlyWithWings()); duck.setQuackBehavior(new Quack()); duck.display(); duck.performFly(); duck.performQuack(); } @Test public void testRebberDuck(){ Duck duck=new RebberDuck(); duck.setFlyBehavior(new FlyNoWay()); duck.setQuackBehavior(new Squack()); duck.display(); duck.performFly(); duck.performQuack(); } }
上面的例子其實就是一個策略模式的應用,不一樣的鴨子有不一樣的飛行策略和叫的方式,因此單獨定義飛行和叫的接口即策略模式中的策略接口,不一樣的的叫聲或者飛行方式實現接口即不一樣的策略類。鴨子Duck類中組合這些策略,即Duck就是策略中的上下文,全部的變化行爲都是在此定義。後期擴展其餘鴨子時只需繼承Duck 而後設定這個鴨子擁有的行爲便可有很大的靈活性。設計
涉及到的設計原則3d
多用組合,少用繼承(使用組合系統具備很大的彈性,不只能夠將算法封裝成類更能夠在運行時動態改變行爲)code