設計模式之禪(1)-策略模式
文章目錄
更多關於設計模式的文章請點選:設計模式之禪(0)-目錄頁
一、進一步的改進
上面的動物園例子似乎已經足夠地完善了,但是仔細想想並不是這樣:當另一個SmallDog
被建立時,它實現了BarkBehavior
介面,但是它需要在自身的程式碼中去重寫這個bark()
方法,這個bark()
方法的具體實現暴露在了SmallDog
類中,當我們需要修改SmallDog
的bark()
方法實現時,我們需要在這個類中去修改程式碼,這就造成了硬編碼問題,那麼應該怎麼解決呢?
這裡引申出策略模式
的一個重要思想:使用組合,而不是實現
- 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());
}
執行結果: