從造鴨子這件事扯到策略模式(內含freestyle)

策略模式:

前言:

做者:韓數html

Github:github.com/hanshuaikan…java

時間:2019-01-26git

JDK版本:1.8github

定義:

定義一系列的算法,把它們一個個封裝起來,而且使它們可相互替換。本模式使得算法可獨立於使用它的客戶而變化。算法

適用範圍:

1.在一個系統中,有不少類似的類,而區分這些類的僅僅是不一樣的行爲。那麼策略模式能夠像電腦主機同樣模塊化的讓一個對象在不一樣的行爲中選擇一種一種行爲。編程

二、一個系統須要動態地在幾種算法中選擇一種。設計模式

三、若是一個對象有不少的行爲,若是不用恰當的模式,這些行爲就只好使用多重的條件選擇語句來實現。安全

優缺點:

優勢:模塊化

代碼耦合度比較底,相對來講比較靈活一些測試

能夠避免使用if else多重判斷語句

比較有彈性,可擴展性比較好

缺點

策略類會比較多,以後的代碼實戰中會發現這個問題

全部策略類都須要對外暴露

前提引入:

韓數首創之對話流:

老闆: 阿呆,你去給我編寫一個鴨子類(嚴重吐槽,請你們不要想歪,本書依靠head frist系列書籍,爲了不讀者讀書的時候代碼和書籍有不一樣的地方影響理解,故沒有修正)

阿呆: 心裏戲(不就寫個實體類嗎。寫個Duck類,而後把鴨子外貌,飛,叫這樣的特徵定義了,方法實現了就OK了,Nice,完美),老闆沒問題,保證完成任務!

a week has later.... 阿呆信心滿滿的把寫好的Duck類交給了老闆。

老闆: 不錯,寫的不錯,哎呀,但是,我忽然又想要一隻橡皮鴨,這隻鴨子,不會飛,吱吱叫,我小時候最喜歡的玩具,這樣吧,你去寫寫這個啥橡皮鴨吧。

阿呆:(心裏戲: 這橡皮鴨,這,跟我上次寫的那個鴨子不是一個品種啊,怎麼還吱吱叫,鴨子不都嘎嘎嘎叫嗎,算了,不就是再寫一個類繼承Duck類嗎,把fly,quack,display這三個方法覆蓋重寫了就行了,Nice,完美,我簡直是一個天才!)老闆沒問題,保證完成任務!

a week has later.... 阿呆信心滿滿的把寫好的RubberDuck類交給了老闆。

老闆: 不錯,真好,對了,阿呆呀,我那個侄女,她喜歡那個綠毛鴨,會飛,咕咕叫,頭上長綠毛的那種,你看能寫麼?

阿呆:(心裏戲:MMP,略) 老闆沒問題,保證完成任務!

a week has later...

老闆: 那個黑天鴨...

阿呆:(心裏戲:emmmmmp) 老闆沒問題,保證完成任務!

老闆: 那個七小天鴨...

阿呆:(心裏戲:emmmmmp) 老闆沒問題,保證完成任務!

老闆: 那個派大鴨...

阿呆:(心裏戲:emmmmmp) 老闆沒問題,保證完成任務!

a year has later...

阿呆:卒

這麼玩兒下去確定不行,只經過繼承,必然能夠完成老闆的要求,萬一有一萬隻不一樣品種的鴨子,不敢往下想了,並且Duck是全部類的父類,這要是Duck改一點點,想到後面還有幾萬個Duck的孩子要改,不由倒吸一口涼氣,這是,阿呆的弟弟二呆出場了,說:

這世間鴨子千千萬,不過數種,記得我以前給你講那個電腦主機的故事麼,把全部零件設計成可拆卸更換的模塊

只留下那個你們通用的模塊不要動,在鴨子身上就是游泳,哪一種鴨子不會游泳?你說,其餘的,飛呀,叫什麼的,咱們單獨分離出來,最後老闆要啥鴨子,咱們給他組裝一下不就得了。

此時,設計模式中一句寶典浮出水面,那就是:分離變和不變的部分。

你們聽了不由嘖嘖稱讚,紛紛嘆道妙呀,妙呀,真是妙啊!

代碼實戰:

面目一新後的鴨子類:

public abstract class Duck {

	/* * 面向超類編程,主類Duck只保留全部鴨子通用不變的特徵好比游泳 * 變化的部分單獨封裝,提升代碼的彈性,避免由於單一的向下繼承 * 形成的代碼的靈活性下降,避免過於耦合狀況的發生。 */
	
	FlyBehavior flyBehavior;
	QuackBehavior quackBehavior;
 
	public Duck() {
	}
 
	
	//定義set方法,能夠動態的設定鴨子飛行的行爲
	public void setFlyBehavior (FlyBehavior fb) {
		flyBehavior = fb;
	}
	
	//定義set方法,能夠動態的設定鴨子飛行的行爲
	public void setQuackBehavior(QuackBehavior qb) {
		quackBehavior = qb;
	}
 
	//鴨子的外表,這裏定義爲抽象方法,父類只作聲明,不負責實現
	abstract void display();
 
    //鴨子的行爲,Duck不適合實現,交給相應的模塊實現。
	public void performFly() {
		flyBehavior.fly();
	}
 
	public void performQuack() {
		quackBehavior.quack();
	}
    
    
    //全部鴨子都會游泳
	public void swim() {
		System.out.println("All ducks float, even decoys!");
	}
}

複製代碼

可能會有人不太懂,FlyBehavior flyBehavior; QuackBehavior quackBehavior;是什麼意思,你想啊,雖然顯卡,CPU,音響,內存條都模塊化了,可是也總的留個插頭方便接入不是。

定義飛行行爲的接口,爲啥是接口呢?不是類,面向接口(超類)編程,能夠更好的利用面向對象中的多態,第二個也能夠提升程序相互調用中的安全性。提升程序的靈活性,可擴展性。

public interface FlyBehavior {
	public void fly();
}

複製代碼

同理叫聲接口:

public interface QuackBehavior {
	public void quack();
}
複製代碼

好比嘎嘎叫的鴨子,咱們就定義一個Quack類實現QuackBehavior的接口,並編寫quack方法的實現爲嘎嘎叫,吱吱叫的鴨子,咱們就定義一個Squeak類實現QuackBehavior的接口,並編寫quack方法的實現爲吱吱叫,等等,咕咕叫,喔喔叫,哇我叫,等等等等等,你開心就好。飛的行爲同理。

/*** * * 定義鴨子叫聲是嘎嘎嘎的行爲 * */


public class Quack implements QuackBehavior {
	public void quack() {
		System.out.println("嘎嘎嘎");
	}
}



/*** * * @author hansu * 定義鴨子吱吱叫的行爲 * */


public class Squeak implements QuackBehavior {
	public void quack() {
		System.out.println("吱吱吱");
	}
}


複製代碼
/*** * * 定義鴨子不會飛的行爲 * * */

public class FlyNoWay implements FlyBehavior {
	public void fly() {
		System.out.println("I can't fly");
	}
}



/*** * * 定義鴨子是會飛的行爲 * */

public class FlyWithWings implements FlyBehavior {
	public void fly() {
		System.out.println("我會飛!哈哈哈");
	}
}


複製代碼

好了,如今模塊是寫好了,但是,咱們怎麼樣編寫鴨子的子類把這些模塊裝上去呢?二呆緩緩說,急啥,且聽我娓娓道來。

喲,要是想把這些模塊來組裝

那你就要深刻進去它的心房

把模塊放入構造器中

變成一把直接就上膛的手槍

yo,freestyle

好比橡皮鴨的特徵是吱吱叫,不會飛,身子是橡皮作的,因而就把FlyNoWay,Squeak模塊組裝一下,而後只需實現一下父類Duck的display方法就會獲得一隻嶄新的徹底知足甲方要求的橡皮鴨了!

以下:

/*** * * demo1:橡皮鴨,特徵,不會飛,吱吱叫 * */

public class RubberDuck extends Duck {
 
	public RubberDuck() {
		/* * 注:由於RubberDuck繼承Duck類,全部Duck類中定義的 * flyBehavior和quackBehavior能夠直接賦值 */
		//定義橡皮鴨不會飛的行爲
		flyBehavior = new FlyNoWay();
		//定義橡皮鴨吱吱叫的行爲
		quackBehavior = new Squeak();
	}
 
	public void display() {
		System.out.println("我是一個橡皮鴨,個人身體是橡皮作噠");
	}
}

複製代碼

編寫測試代碼Text:

public class Text {
	
	public static void main(String[] args) {
		Text t = new Text();
		t.rubberDuckDemoText();
		
		System.out.println("\n如今有請活的鴨子閃亮登場!\n");
		
		t.liveDuckDemoText();
	}
	
	
	
	public void rubberDuckDemoText() {
		
		RubberDuck rubberDuck = new RubberDuck();
		rubberDuck.display();
		rubberDuck.performFly();
		rubberDuck.performQuack();

		
		
		
	}
	
	public void liveDuckDemoText() {
		
		LiveDuck liveDuck = new LiveDuck();
		liveDuck.display();
		liveDuck.performFly();
		liveDuck.performQuack();
	
		
		
		
	}
	

}

複製代碼

Out:

我是一個橡皮鴨,個人身體是橡皮作噠 I can't fly 吱吱吱

如今有請活的鴨子閃亮登場!

我是一隻活鴨子 我會飛!哈哈哈 嘎嘎嘎

最後,二呆和老闆幸福的生活在了一塊兒。

實戰總結:

在這裏你們就會發現了,雖然這樣的確比繼承單一Duck類重寫方法方便高效了不少,可是若是鴨子特徵超級多的話,也須要編寫超級多的行爲類,同時,每一個行爲類都必須是可實例化的,這針對某些狀況來講並不太適合,可是,設計模式有二十七種呢,更不要說其餘設計模式了,更是多到數不勝數,因此在合適的狀況下選擇合適的設計模式能夠顯著提升咱們代碼的效率和質量,這點是毋庸置疑的。

寫在最後:

歡迎你們給小星星,您的星星是我寫下去的不竭動力!

源碼部分請移步本人Github下載:

Github地址:

Github:github.com/hanshuaikan…

參考資料:

菜鳥教程:www.runoob.com/design-patt…

Head frist of 設計模式

相關文章
相關標籤/搜索