設計模式--策略模式

策略模式主要是抽象出不變的部分代碼,然後定義算法簇將不同的算法分別封裝起來,這就可以使得客戶端不會受到算法改變的影響。這樣對新增的需求就會由彈性支持,並不需要重構代碼,只需要將該算法封裝好就好了。其實官方的定義是策略模式將可變的部分從程序中抽象分離成算法接口,在該接口下分別封裝一系列的算法實現,並且使得他們可以相互替換,從而導致客戶端程序獨立於算法的改變。

策略模式的實現

我們利用下面的例子來展示出策略模式的使用
首先我們需要編寫一些實現類。
Duck.java:鴨子的總括,所有鴨子有的特性都在裏面

package com.xjh.strategy;

public abstract class Duck {
	
	/**
	 * 通用行爲,由超類實現
	 */
	public void quack() {
		System.out.print("嘎嘎嘎");
	}
	
	/**
	 * 特殊行爲,聲明爲abstract,由子類實現
	 */
	public abstract void display();
	
}

MallardDuck.java和RedheadDuck.java:鴨子的具體實現

package com.xjh.strategy;

public class MallardDuck extends Duck {
	
	public MallardDuck() {
		super();
	}

	@Override
	public void display() {
		// TODO Auto-generated method stub
		System.out.println("我的脖子是綠色的");
	}

}
package com.xjh.strategy;

public class RedheadDuck extends Duck {
	
	public RedheadDuck() {
		super();
	}

	@Override
	public void display() {
		// TODO Auto-generated method stub
		System.out.println("我的頭是紅色的");
	}

}

假如我們想讓鴨子增加一個飛行的能力有什麼辦法呢。肯定很多人都會想到在父類中定義飛行的方法,這樣子類就具有了飛行的方法了。
繼承

public void fly() {
	System.out.print("fly");
}

的確這樣可以實現我們想要的效果,並且簡單易用,但是我們如果這樣做了就不具有靈活性,對未來變更支持的能力變差,所以我們不會去使用這種方法,萬一後面我們發現有鴨子不會飛怎麼辦。那我們就會想到前面我們display的實現方法。在父類中提供抽象方法,強迫子類實現自己的飛行方法。
抽象方法

public abstract void fly();

但是我們要想到我們的display方法是每種子類有不同的屬性,但是對於飛行,我們要對所有的會飛行的子類都實現一遍相同的代碼,這樣是不是很麻煩呢。並且我們有相同代碼而不進行代碼複用,那以後這部分代碼出現bug,是不是需要改很多的代碼。
那就要提到組合的概念了:在類中增加一個私有域,引用另一個已有的類的實例,通過調用引用實例的方法從而獲得新的功能,這種設計被稱作組合。
組合
將飛行行爲抽象爲接口,下面就是策略模式中重要的抽象策略類
FlyingStragety.java

package com.xjh.strategy;

public interface FlyingStragety {
	
	void performFly();
}

然後我們在父類中持有該接口,並由該接口代理飛行行爲。

private FlyingStragety flyingStragety;public void setFlyingStragety(FlyingStragety flyingStragety) {
	this.flyingStragety = flyingStragety;
}

public void fly() {
	flyingStragety.performFly();
}

因爲我們是調用接口的方法,並且我們接口是通過傳參傳進來的,所以更易於維護以及代碼的複用。
之後我們就要定義接口的實現了,這就是具體策略類
FlyWithWin.java

package com.xjh.strategy;

public class FlyWithWin implements FlyingStragety {

	@Override
	public void performFly() {
		// TODO Auto-generated method stub
		System.out.println("翅膀飛行");
	}

}

然後我們在MallardDuck.java和RedheadDuck.java將相應的接口實例傳進去。

super.setFlyingStragety(new FlyWithWin());

如果遇到了沒有飛行能力的子類怎麼辦,我們就需要重新編寫一個FlyingStragety 接口的實現類。
FlyWithWin.java

package com.xjh.strategy;

public class FlyWithWin implements FlyingStragety {

	@Override
	public void performFly() {
		// TODO Auto-generated method stub
		System.out.println("不會飛行");
	}

}

RubberDuck.java

package com.xjh.strategy;

public class RubberDuck extends Duck {
	
	public RubberDuck() {
		super();
		super.setFlyingStragety(new FlyNoWay());
	}

	@Override
	public void display() {
		// TODO Auto-generated method stub
		System.out.println("我全身發黃,嘴巴很紅");
	}
	
	public void quack() {
		System.out.print("我不會叫");
	}

}

在這裏我們就能看到策略模式的好處了,fly我們自需要new出一個新編寫的接口實現類就好了,但是quack方法我們需要重寫,如果我們忘記了重寫,那橡膠鴨就會叫了,這就有了BUG了。

策略模式的優缺點

策略模式的優點:

  • 使用了組合,使得架構更加靈活
  • 富有彈性,可以較好的應對變化(開閉原則)
  • 代碼複用性(相對於繼承)
  • 消除大量的條件語句

策略模式的缺點:

  • 客戶代碼需要了解每個策略實現的細節
  • 增加了對象的數目

適用場景

  1. 當許多相關的類裏面的內容僅僅是行爲差異
  2. 當運行時選取不同的算法變體
  3. 當發現通過多個判斷語句來選取不同行爲的時候
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章