1. 程式人生 > >設計模式之禪(1)-策略模式

設計模式之禪(1)-策略模式

文章目錄


更多關於設計模式的文章請點選設計模式之禪(0)-目錄頁


一、進一步的改進

上面的動物園例子似乎已經足夠地完善了,但是仔細想想並不是這樣:當另一個SmallDog被建立時,它實現了BarkBehavior介面,但是它需要在自身的程式碼中去重寫這個bark()方法,這個bark()方法的具體實現暴露在了SmallDog類中,當我們需要修改SmallDogbark()方法實現時,我們需要在這個類中去修改程式碼,這就造成了硬編碼問題,那麼應該怎麼解決呢?

這裡引申出策略模式的一個重要思想:使用組合,而不是實現

  • BigDogBark實現類
/**
 * @Auther: ARong
 * @Date: 2018/11/17 23:10
 * @Description:
 */
public class BigDogBark implements BarkBehavior {

    @Override
    public void bark() {
        System.out.println("Big Dog 汪汪汪...");
    }
}
  • BigDog可修改為
/**
 * @Auther: ARong
 * @Date: 2018/11/17 11:09
 * @Description: com.iteason.Animal.BigDog 繼承 Animal的所有屬性和方法並實現BarkBehavior
 */
public class BigDog extends Animal { private BarkBehavior barkBehavior; //構造方法 public BigDog(String name) { super(name); //在執行時將BigDogBark向上轉型為BarkBehavior barkBehavior = new BigDogBark(); } public BigDog() { } //將bark()方法的具體實現委託給BarkBehavior的子類 public
void performBark(){ barkBehavior.bark(); } public BarkBehavior getBarkBehavior() { return barkBehavior; } public void setBarkBehavior(BarkBehavior barkBehavior) { this.barkBehavior = barkBehavior; } }

BigDog類中組合了一個BarkBehavior的介面,在構造方法中新建一個BarkBehavior的實現類BigDogBark通過面向物件的特徵:多型,在執行時確定由誰實現了BarkBehavior介面,並且將執行動作委託給了performBark()方法去呼叫barkBehavior.bark(),這就是一個簡單的策略模式的應用了。

以上關係可用UML關係圖來表達:
在這裡插入圖片描述

二、用策略模式組織類關係例項

在下面,你將看到一堆雜亂的類與介面,這是取自一個動作冒險遊戲。你將看到代
表遊戲角色的類,以及武器行為的類。每個角色一次只能使用一個武器,但是可以
在遊戲的過程中換武器。你的工作是要弄清楚這一切…

這是HeadFirst設計模式中的一個問題,可以使用策略模式,畫出一個UML圖來表示他們的關係:用Character作為角色的超類,裡邊含有角色的共同屬性以及可變的戰鬥武器介面、戰鬥模式介面物件;FightBehavior是戰鬥模式的介面,Quene和Random分別實現了佇列戰鬥模式和隨機戰鬥模式;WeaponBehavior是戰鬥武器介面,KnifeBehavior和GanBehavior分別是使用劍、槍作為武器。

在這裡插入圖片描述
* Character超類

/**
 * @Auther: ARong
 * @Date: 2018/11/17 16:35
 * @Description: 角色超類,定義了角色的名字和武器使用方式以及戰鬥行為
 */
public abstract class Character {
    //角色名字
    private String name;

    //武器使用方式
    private WeaponBehavior weaponBehavior;

    //戰鬥行為
    private FightBehavior fightBehavior;

 

    //構造方法
    public Character(String name) {
        this.name = name;
    }

    public Character() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public WeaponBehavior getWeaponBehavior() {
        return weaponBehavior;
    }

    public void setWeaponBehavior(WeaponBehavior weaponBehavior) {
        this.weaponBehavior = weaponBehavior;
    }

    public FightBehavior getFightBehavior() {
        return fightBehavior;
    }

    public void setFightBehavior(FightBehavior fightBehavior) {
        this.fightBehavior = fightBehavior;
    }
}
  • WeaponBehavior介面
/**
 * @Auther: ARong
 * @Date: 2018/11/17 16:37
 * @Description: 定義了角色的武器使用方式
 */
public interface WeaponBehavior {
    public void userWeapon();
}
  • FightBehavior介面
/**
 * @Auther: ARong
 * @Date: 2018/11/17 16:38
 * @Description: 定義了角色的戰鬥行為
 */
public interface FightBehavior {
    public void fight();
}
  • KnifeBehavior實現類
/**
 * @Auther: ARong
 * @Date: 2018/11/17 16:42
 * @Description: WeaponBehavior的實現類,使用劍作為武器
 */
public class KnifeBehavior implements WeaponBehavior{

    @Override
    public void userWeapon() {
        System.out.println("使用劍戰鬥");
    }
}
  • GanBehavior實現類
/**
 * @Auther: ARong
 * @Date: 2018/11/17 16:43
 * @Description: WeaponBehavior的實現類,使用槍作為武器
 */
public class GanBehavior implements WeaponBehavior{

    @Override
    public void userWeapon() {
        System.out.println("使用槍戰鬥");
    }
}
  • Quene實現類
/**
 * @Auther: ARong
 * @Date: 2018/11/17 16:40
 * @Description: FightBehavior的實現類,使用佇列戰鬥行為
 */
public class Quene implements FightBehavior{

    @Override
    public void fight() {
        System.out.println("佇列戰鬥");
    }
}
  • Random實現類
/**
 * @Auther: ARong
 * @Date: 2018/11/17 16:42
 * @Description: FightBehavior的實現類,使用隨機戰鬥行為
 */
public class Random implements FightBehavior{
    @Override
    public void fight() {
        System.out.println("隨機戰鬥");
    }
}
  • GanFighter角色類
/**
 * @Auther: ARong
 * @Date: 2018/11/17 17:01
 * @Description: GanFighter是一個使用槍和隨機戰鬥方式的角色
 */
public class GanFighter extends Character{

    //構造方法
    public GanFighter(String name){
        super.setName(name);
        super.setWeaponBehavior(new GanBehavior());
        super.setFightBehavior(new Random());
    }

    public GanFighter(){

    }


    //使用武器
    public void performWeapon(){
        super.getWeaponBehavior().userWeapon();
    }

    //戰鬥方式
    public void performFight(){
        super.getFightBehavior().fight();
    }

}

GanFight是一個使用槍和隨機戰鬥方式的角色,所以在它的構造方法中,為它的戰鬥武器和方式介面建立了具體的實現類,使他擁有了以槍為武器和隨機戰鬥的方式。

使用GanFighter類:

@Test
    public void userGanFighter(){
        GanFighter g_fighter = new GanFighter("G_Fighter");

        System.out.println(g_fighter.getName());
        g_fighter.performWeapon();
        g_fighter.performFight();
    }

在這裡插入圖片描述

如果你想讓角色能更加地方便建立和使用,可以在使用方法時傳遞介面實現類的方式,從而達到要求:

/**
 * @Auther: ARong
 * @Date: 2018/11/17 16:44
 * @Description: Fighter類是Character的子類,並且在構造方法中需要例項化WeaponBehavior介面和FightBehavior介面的子類
 */
public class Fighter extends Character{
    //構造方法
    public Fighter(String n){
        //在例項化Fighter時指定Fighter的名字
        super.setName(n);
    }

    public Fighter(){

    }

    //戰鬥武器
    public void performWeapon(WeaponBehavior w){
        super.setWeaponBehavior(w);
        super.getWeaponBehavior().userWeapon();
    }

    //戰鬥方式
    public void performFight(FightBehavior f){
        super.setFightBehavior(f);
        super.getFightBehavior().fight();
    }

}

使用Fighter類去建立一個使用劍和隨機戰鬥方式的角色:

@Test
    public void userFighter(){

       Fighter ganFighter = new Fighter("劍神");

        System.out.println(ganFighter.getName());
        //使用劍
        ganFighter.performWeapon(new KnifeBehavior());
        //隨機戰鬥方式
        ganFighter.performFight(new Random());
    }

執行結果:
在這裡插入圖片描述