模式定義 定義一系列演算法,分別封裝起來,讓它們之間可以呼死去那個替換,此模式讓演算法變化,不會影響到使用演算法的客戶 類圖定義 示例 示例來自於Head First上的鴨子例子,一個鴨子的系統,系統中會出現不同的鴨子,一邊游泳一邊叫。綠頭鴨子會飛,會游泳,正常呱呱叫,橡皮鴨子不會飛不會游泳吱吱叫。後期可 ...
模式定義
定義一系列演算法,分別封裝起來,讓它們之間可以呼死去那個替換,此模式讓演算法變化,不會影響到使用演算法的客戶
類圖定義
示例
示例來自於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;
}
}
鴨子具體實現類
/**
* 綠頭鴨子
*
* @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("橡皮鴨子吱吱叫!");
}
}
測試類
/**
* 鴨子測試類
*
* @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 然後設定這個鴨子擁有的行為即可有很大的靈活性。
涉及到的設計原則
- 找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的代碼混在一起
- 針對介面編程,而不是針對實現編程(多態,利用多態程式可以針對超類編程執行時會根據實際的情況執行到真正的行為不會被綁死到超類型的行為上)
多用組合,少用繼承(使用組合系統具有很大的彈性,不僅可以將演算法封裝成類更可以在運行時動態改變行為)