設(shè)計(jì)模式Java語(yǔ)言實(shí)現(xiàn)之策略模式(生動(dòng)有趣版)

策略模式:

前言:

作者:韓數(shù)

Github:https://github.com/hanshuaikang

時(shí)間:2019-01-26

JDK版本:1.8

定義:

定義一系列的算法,把它們一個(gè)個(gè)封裝起來(lái),并且使它們可相互替換。本模式使得算法可獨(dú)立于使用它的客戶而變化。

適用范圍:

1.在一個(gè)系統(tǒng)中,有很多相似的類,而區(qū)分這些類的僅僅是不同的行為。那么策略模式可以像電腦主機(jī)一樣模塊化的讓一個(gè)對(duì)象在不同的行為中選擇一種一種行為。

2、一個(gè)系統(tǒng)需要?jiǎng)討B(tài)地在幾種算法中選擇一種。

3、如果一個(gè)對(duì)象有很多的行為,如果不用恰當(dāng)?shù)哪J?,這些行為就只好使用多重的條件選擇語(yǔ)句來(lái)實(shí)現(xiàn)。

優(yōu)缺點(diǎn):

優(yōu)點(diǎn):

代碼耦合度比較底,相對(duì)來(lái)說(shuō)比較靈活一些

可以避免使用if else多重判斷語(yǔ)句

比較有彈性,可擴(kuò)展性比較好

缺點(diǎn)

策略類會(huì)比較多,之后的代碼實(shí)戰(zhàn)中會(huì)發(fā)現(xiàn)這個(gè)問(wèn)題

所有策略類都需要對(duì)外暴露

前提引入:

韓數(shù)獨(dú)創(chuàng)之對(duì)話流:

老板: 阿呆,你去給我編寫一個(gè)鴨子類(嚴(yán)重吐槽,請(qǐng)大家不要想歪,本書依靠head frist系列書籍,為了避免讀者讀書的時(shí)候代碼和書籍有不同的地方影響理解,故沒(méi)有修正)

阿呆: 內(nèi)心戲(不就寫個(gè)實(shí)體類嗎。寫個(gè)Duck類,然后把鴨子外貌,飛,叫這樣的特征定義了,方法實(shí)現(xiàn)了就OK了,Nice,完美),老板沒(méi)問(wèn)題,保證完成任務(wù)!

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

老板: 不錯(cuò),寫的不錯(cuò),哎呀,可是,我突然又想要一只橡皮鴨,這只鴨子,不會(huì)飛,吱吱叫,我小時(shí)候最喜歡的玩具,這樣吧,你去寫寫這個(gè)啥橡皮鴨吧。

阿呆:(內(nèi)心戲: 這橡皮鴨,這,跟我上次寫的那個(gè)鴨子不是一個(gè)品種啊,怎么還吱吱叫,鴨子不都嘎嘎嘎叫嗎,算了,不就是再寫一個(gè)類繼承Duck類嗎,把fly,quack,display這三個(gè)方法覆蓋重寫了就好了,Nice,完美,我簡(jiǎn)直是一個(gè)天才?。├习鍥](méi)問(wèn)題,保證完成任務(wù)!

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

老板: 不錯(cuò),真好,對(duì)了,阿呆呀,我那個(gè)侄女,她喜歡那個(gè)綠毛鴨,會(huì)飛,咕咕叫,頭上長(zhǎng)綠毛的那種,你看能寫么?

阿呆:(內(nèi)心戲:MMP,略) 老板沒(méi)問(wèn)題,保證完成任務(wù)!

a week has later...

老板: 那個(gè)黑天鴨...

阿呆:(內(nèi)心戲:emmmmmp) 老板沒(méi)問(wèn)題,保證完成任務(wù)!

老板: 那個(gè)七小天鴨...

阿呆:(內(nèi)心戲:emmmmmp) 老板沒(méi)問(wèn)題,保證完成任務(wù)!

老板: 那個(gè)派大鴨...

阿呆:(內(nèi)心戲:emmmmmp) 老板沒(méi)問(wèn)題,保證完成任務(wù)!

a year has later...

阿呆:卒

這么玩兒下去肯定不行,只通過(guò)繼承,必然可以完成老板的要求,萬(wàn)一有一萬(wàn)只不同品種的鴨子,不敢往下想了,而且Duck是所有類的父類,這要是Duck改一點(diǎn)點(diǎn),想到后面還有幾萬(wàn)個(gè)Duck的孩子要改,不禁倒吸一口涼氣,這是,阿呆的弟弟二呆出場(chǎng)了,說(shuō):

這世間鴨子千千萬(wàn),不過(guò)數(shù)種,記得我之前給你講那個(gè)電腦主機(jī)的故事么,把所有零件設(shè)計(jì)成可拆卸更換的模塊

只留下那個(gè)大家通用的模塊不要?jiǎng)?,在鴨子身上就是游泳,哪種鴨子不會(huì)游泳?你說(shuō),其他的,飛呀,叫什么的,我們單獨(dú)分離出來(lái),最后老板要啥鴨子,我們給他組裝一下不就得了。

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

大家聽(tīng)了不禁嘖嘖稱贊,紛紛嘆道妙呀,妙呀,真是妙?。?/p>

代碼實(shí)戰(zhàn):

煥然一新后的鴨子類:

public abstract class Duck {
?
 /*
 * 面向超類編程,主類Duck只保留所有鴨子通用不變的特征比如游泳
 * 變化的部分單獨(dú)封裝,提高代碼的彈性,避免因?yàn)閱我坏南蛳吕^承
 * 造成的代碼的靈活性降低,避免過(guò)于耦合情況的發(fā)生。
 */

 FlyBehavior flyBehavior;
 QuackBehavior quackBehavior;

 public Duck() {
 }

 //定義set方法,可以動(dòng)態(tài)的設(shè)定鴨子飛行的行為
 public void setFlyBehavior (FlyBehavior fb) {
 flyBehavior = fb;
 }

 //定義set方法,可以動(dòng)態(tài)的設(shè)定鴨子飛行的行為
 public void setQuackBehavior(QuackBehavior qb) {
 quackBehavior = qb;
 }

 //鴨子的外表,這里定義為抽象方法,父類只做聲明,不負(fù)責(zé)實(shí)現(xiàn)
 abstract void display();

 //鴨子的行為,Duck不適合實(shí)現(xiàn),交給相應(yīng)的模塊實(shí)現(xiàn)。
 public void performFly() {
 flyBehavior.fly();
 }

 public void performQuack() {
 quackBehavior.quack();
 }

 //所有鴨子都會(huì)游泳
 public void swim() {
 System.out.println("All ducks float, even decoys!");
 }
}

可能會(huì)有人不太懂,F(xiàn)lyBehavior flyBehavior; QuackBehavior quackBehavior;是什么意思,你想啊,雖然顯卡,CPU,音響,內(nèi)存條都模塊化了,但是也總的留個(gè)插頭方便接入不是。

定義飛行行為的接口,為啥是接口呢?不是類,面向接口(超類)編程,可以更好的利用面向?qū)ο笾械亩鄳B(tài),第二個(gè)也可以提高程序相互調(diào)用中的安全性。提高程序的靈活性,可擴(kuò)展性。

public interface FlyBehavior {
 public void fly();
}

同理叫聲接口:

public interface QuackBehavior {
 public void quack();
}

比如嘎嘎叫的鴨子,我們就定義一個(gè)Quack類實(shí)現(xiàn)QuackBehavior的接口,并編寫quack方法的實(shí)現(xiàn)為嘎嘎叫,吱吱叫的鴨子,我們就定義一個(gè)Squeak類實(shí)現(xiàn)QuackBehavior的接口,并編寫quack方法的實(shí)現(xiàn)為吱吱叫,等等,咕咕叫,喔喔叫,哇我叫,等等等等等,你開(kāi)心就好。飛的行為同理。

/***
 * 
 * 定義鴨子叫聲是嘎嘎嘎的行為
 * 
 */
?
?
public class Quack implements QuackBehavior {
 public void quack() {
 System.out.println("嘎嘎嘎");
 }
}
?
?
?
/***
 * 
 * @author hansu
 * 定義鴨子吱吱叫的行為
 * 
 */
?
?
public class Squeak implements QuackBehavior {
 public void quack() {
 System.out.println("吱吱吱");
 }
}
?
/***
 * 
 * 定義鴨子不會(huì)飛的行為
 * 
 *
 */
?
public class FlyNoWay implements FlyBehavior {
 public void fly() {
 System.out.println("哎,難過(guò),我不會(huì)飛");
 }
}
?
?
?
/***
 * 
 * 定義鴨子是會(huì)飛的行為
 *
 */
?
public class FlyWithWings implements FlyBehavior {
 public void fly() {
 System.out.println("我會(huì)飛!哈哈哈");
 }
}
?

好了,現(xiàn)在模塊是寫好了,可是,我們?cè)趺礃泳帉戻喿拥淖宇惏堰@些模塊裝上去呢?二呆緩緩說(shuō),急啥,且聽(tīng)我娓娓道來(lái)。

喲,要是想把這些模塊來(lái)組裝

那你就要深入進(jìn)去它的心房

把模塊放入構(gòu)造器中

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

yo,freestyle

比如橡皮鴨的特征是吱吱叫,不會(huì)飛,身子是橡皮做的,于是就把FlyNoWay,Squeak模塊組裝一下,然后只需實(shí)現(xiàn)一下父類Duck的display方法就會(huì)得到一只嶄新的完全滿足甲方要求的橡皮鴨了!

如下:

/***
 * 
 * demo1:橡皮鴨,特征,不會(huì)飛,吱吱叫
 *
 */
?
public class RubberDuck extends Duck {

 public RubberDuck() {
 /*
 * 注:因?yàn)镽ubberDuck繼承Duck類,所有Duck類中定義的
 * flyBehavior和quackBehavior可以直接賦值
 */
 //定義橡皮鴨不會(huì)飛的行為
 flyBehavior = new FlyNoWay();
 //定義橡皮鴨吱吱叫的行為
 quackBehavior = new Squeak();
 }

 public void display() {
 System.out.println("我是一個(gè)橡皮鴨,我的身體是橡皮做噠");
 }
}

編寫測(cè)試代碼Text:

public class Text {

 public static void main(String[] args) {
 Text t = new Text();
 t.rubberDuckDemoText();

 System.out.println("\n現(xiàn)在有請(qǐng)活的鴨子閃亮登場(chǎng)!\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:

我是一個(gè)橡皮鴨,我的身體是橡皮做噠 I can't fly 吱吱吱

現(xiàn)在有請(qǐng)活的鴨子閃亮登場(chǎng)!

我是一只活鴨子 我會(huì)飛!哈哈哈 嘎嘎嘎

最后,二呆和老板幸福的生活在了一起。

實(shí)戰(zhàn)總結(jié):

在這里大家就會(huì)發(fā)現(xiàn)了,雖然這樣的確比繼承單一Duck類重寫方法方便高效了很多,但是如果鴨子特征超級(jí)多的話,也需要編寫超級(jí)多的行為類,同時(shí),每個(gè)行為類都必須是可實(shí)例化的,這針對(duì)某些情況來(lái)說(shuō)并不太適合,但是,設(shè)計(jì)模式有二十七種呢,更不要說(shuō)其他設(shè)計(jì)模式了,更是多到數(shù)不勝數(shù),所以在合適的情況下選擇合適的設(shè)計(jì)模式可以顯著提高我們代碼的效率和質(zhì)量,這點(diǎn)是毋庸置疑的。

寫在最后:

歡迎大家給小星星,您的星星是我寫下去的不竭動(dòng)力!

源碼部分請(qǐng)移步本人Github下載:

Github地址:

Github:https://github.com/hanshuaikang/design-pattern-java

參考資料:

菜鳥(niǎo)教程:http://www.runoob.com/design-pattern/strategy-pattern.html

Head frist of 設(shè)計(jì)模式

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文參照《Head First 設(shè)計(jì)模式》,轉(zhuǎn)載請(qǐng)注明出處對(duì)于整個(gè)系列,我們按照這本書的設(shè)計(jì)邏輯,使用情景分析的方...
    詭異的葉子閱讀 710評(píng)論 0 5
  • Git命令大全 git config 配置 Git 的相關(guān)參數(shù)。 Git 一共有3個(gè)配置文件: 1. 倉(cāng)庫(kù)級(jí)的配置...
    笑葉林閱讀 144,152評(píng)論 11 141
  • 2016年,經(jīng)歷的事不多,后半年只有一件——考研。 期間搖擺不定,但從沒(méi)質(zhì)疑過(guò)自己的方向。 也不知道該說(shuō)些什么,這...
    格格曙閱讀 223評(píng)論 0 0
  • #幸福是需要修出來(lái)的~每天進(jìn)步1%~幸福實(shí)修13班~22唐潔# 20180102(36/60) 【幸福三朵玫瑰】 ...
    你謝謝閱讀 184評(píng)論 0 2
  • 昨天一位兩個(gè)孩子的爸爸很困惑的問(wèn)我兩個(gè)問(wèn)題,1.他說(shuō)他的兩個(gè)孩子很貪玩,靜不下心來(lái)學(xué)習(xí);2、他在家里的時(shí)候和不...
    47c5277e96f6閱讀 219評(píng)論 0 0

友情鏈接更多精彩內(nèi)容