設計模式---策略者模式

--------------------------------------------------根據《Head First 設計模式》整理記憶--------------------------------------------------------------------


從一個添加鴨子的行爲講起,一開始採用的是繼承:

DUCK父類:

<span style="font-size:14px;">package StrategyPattern;

/**
 * @author 作者 E-mail:
 * @version 創建時間:2015年7月8日 上午10:37:42 類說明
 */
public class Duck {
	public void quack() {
		System.out
				.println("-------------------Duck quack-----------------------");
	}

	public void swim() {
		System.out
				.println("-------------------Duck swim----------------------");
	}

	public void display() {
		System.out
				.println("-------------------Duck display-------------------");
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}
</span>

MallardDuck子類:

<span style="font-size:14px;">package StrategyPattern;

/**
 * @author 作者 E-mail:
 * @version 創建時間:2015年7月8日 上午10:40:05 類說明
 */
public class MallardDuck extends Duck {
	public void display() {
		System.out
				.println("-------------------------MallardDuck display---------------------------");
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}
</span>

ReadheadDuck子類:

<span style="font-size:14px;">package StrategyPattern;

/**
 * @author 作者 E-mail:
 * @version 創建時間:2015年7月8日 上午10:41:13 類說明
 */
public class RedheadDuck extends Duck{
	public void display() {
		System.out
				.println("-------------------------RedheadDuck display---------------------------");
	}

	public static void main(String[] args) {
		RedheadDuck aRedheadDuck = new RedheadDuck();
		aRedheadDuck.quack();
	}

}
</span>

法一:後來需要添加一個fly行爲,首先想到的是直接在父類裏面添加fly方法,課本上說造成了滿屏飛的鴨子(PS:這個我們一般不會犯這個錯誤,子類需要Override一下的)


如同dispal一樣去實現這個行爲:

缺點:

1.代碼在多個子類重複;

2.運行時的行爲不容易改變;

3.很難知道所有鴨子的行爲;

4.改變會牽一髮而動全身;


法二:MallardDuck繼承Duck父類,然後實現Flyable接口,當鴨子種類很多時候噩夢發生,有很多的鴨子的飛行行爲是相通的;

設計原則一:

找出其中可能需要變化之處,把他們獨立出來,不要和那些需要變化的代碼混在一起。


設計原則二:

針對接口編程,而不是針對實現編程。---關鍵在於利用多態---


法三:測試Duck的代碼:

Duck類有兩個行爲類接口的引用:

package StrategyPattern;

/**
 * @author 作者 E-mail:
 * @version 創建時間:2015年7月8日 上午10:37:42 類說明
 */
public abstract class Duck  {
	FlyBehavior flyBehavior;
	QuackBehavior quackBehavior;

	public void swim() {
		System.out
				.println("-------------------Duck swim----------------------");
	}

	public void display() {
		System.out
				.println("-------------------Duck display-------------------");
	}

	public void performQuack() {//委託給行爲類
		quackBehavior.quack();
	}

	public void performFly() {//委託給行爲類
		flyBehavior.fly();
	}
}

兩個接口及其實現類爲:

第一個飛行接口及其實現:

public interface FlyBehavior {
	public void fly();
}
public class FlyNoWay {
<span style="white-space:pre">	</span>public void fly() {
<span style="white-space:pre">		</span>System.out
<span style="white-space:pre">				</span>.println("-------------------I can't fly-------------------");
<span style="white-space:pre">	</span>}
}
public class FlyWithWings implements FlyBehavior {
<span style="white-space:pre">	</span>public void fly() {
<span style="white-space:pre">		</span>System.out
<span style="white-space:pre">				</span>.println("-------------------FlyWithWings-------------------");
<span style="white-space:pre">	</span>}
}
第一個鴨子叫接口及其實現:

public interface QuackBehavior {
	public void quack();
}
public class MuteQuack implements QuackBehavior{
<span style="white-space:pre">	</span>public void quack() {
<span style="white-space:pre">		</span>System.out
<span style="white-space:pre">				</span>.println("-------------------MuteQuack----------------------");
<span style="white-space:pre">	</span>}
}
public class Quack implements QuackBehavior {
<span style="white-space:pre">	</span>public void quack() {
<span style="white-space:pre">		</span>System.out
<span style="white-space:pre">				</span>.println("-------------------quack----------------------");
<span style="white-space:pre">	</span>}
}
public class Squeak implements QuackBehavior {
<span style="white-space:pre">	</span>public void quack() {
<span style="white-space:pre">		</span>System.out
<span style="white-space:pre">				</span>.println("-------------------Squeak----------------------");
<span style="white-space:pre">	</span>}
}

編寫測試用例:

package StrategyPattern;

/**
 * @author 作者 E-mail:
 * @version 創建時間:2015年7月8日 上午10:40:05 類說明
 */
public class MallardDuck extends Duck {

	public MallardDuck() {
		quackBehavior = new Quack();
		flyBehavior = new FlyWithWings();
	}

	public void display() {
		System.out
				.println("-------------------MallardDuck display-------------------");
	}

	public static void main(String[] args) {
		Duck mallard = new MallardDuck();
		mallard.performFly();
		mallard.performQuack();

	}
}

法四:動態設定行爲,鴨子的行爲可以動態變化的時候,這一秒旋轉飛,下一秒倒着飛,就是這麼任性,怎麼辦,以爲上面已經把鴨子的行爲在構造器內實例化了,需要設置Setter方法去改變。


Duck父類添加兩個方法去改變相應行爲:

	public void setQuackBehavior(QuackBehavior qb) {//委託給行爲類
		quackBehavior = qb;
	}

	public void setFlyBehavior(FlyBehavior fb) {//委託給行爲類
		flyBehavior = fb;
	}

mallardDuck實例進行動態改變自己行爲

	public static void main(String[] args) {
		Duck mallard = new MallardDuck();				
		mallard.performQuack();
		mallard.performFly();
		mallard.setFlyBehavior(new FlyNoWay());
		mallard.performFly();
	}


最後結果:

-------------------quack----------------------
-------------------FlyWithWings-------------------
-------------------I can't fly-------------------

總結:

 策略者模式定義:定義了算法族,分別封裝起來,讓他們之間可以互相替換,此模式讓算法的變化獨立於使用算法的客戶。(這也就是爲什麼圖3中爲何把“行爲”摸去改爲算法的原因)

     策略者模式的優點:

          1、 提供了一種替代繼承的方法,而且既保持了繼承的優點(代碼重用)還比繼承更靈活(算法獨立,可以任意擴展)。
          2、 避免程序中使用多重條件轉移語句,使系統更靈活,並易於擴展。
          3、 遵守大部分GRASP原則和常用設計原則,高內聚、低偶合。              
         
             策略者模式的缺點:           
           1、 因爲每個具體策略類都會產生一個新類,所以會增加系統需要維護的類的數量。

ps:GRASP(General Responsibility Assignment Software Pattern)是通用職責軟件分配模式。GRASP的核心是自己幹自己能幹的事,自己只幹自己的 事,也就是職責的分配和實現高內聚。用來解決面向對象設計的一些問題。此外GRASP原則還闡述了幾大原則,以後會繼續寫博道來。




源代碼:http://download.csdn.net/detail/bingbing8219/8879481





























發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章