設計模式筆記(一)--策略模式

最近在看設計模式的書籍雷滚,將看到的知識做一個筆記需曾,方便記憶。
這是第一篇。

簡介

設計模式(Design pattern)代表了最佳的實踐呆万。設計模式是開發(fā)人員面臨問題的解決方案商源。這些解決方案是眾多開發(fā)人員經過相當長的一段時間試驗和總結出來的。

什么是策略設計模式

策略模式(Strategy Pattern):定義了算法簇谋减,分別封裝起來牡彻,讓他們之間可以相互替換,此模式讓算法的變化獨立于使用算法的客戶出爹。

... 好吧庄吼,太拗口了。
還是直接看例子吧严就。

場景:
現在有這樣一個需求:現在需要用代碼設計一輛多功能步兵車总寻。
要求如下:

  1. 這個車輛必須可以裝載不同的武器,實現不同的攻擊方式梢为。
  2. 這個車可以安裝不同的輪子渐行,實現不同的移動方式。

一種不好的實現方式

一直不好的方式

代碼實現:

public abstract class 多功能步兵車 {
    public abstract void type();//車輛的類型

    public abstract void attack(); // 攻擊方式

    public abstract void move(); // 移動方式
}
public class 火箭_履帶步兵車 extends 多功能步兵車 {
    @Override
    public void type() {
        System.out.print("我是火箭—履帶—步兵車");
    }

    @Override
    public void attack() {
        System.out.print("我用火箭打死你");
    }

    @Override
    public void move() {
        System.out.print("我是在用履帶奔馳");
    }
}
public class 機槍_輪胎步兵車 extends 多功能步兵車 {
    @Override
    public void type() {
        System.out.print("我是機槍—輪胎—步兵車");
    }

    @Override
    public void attack() {
        System.out.print("我用機槍打死你");
    }

    @Override
    public void move() {
        System.out.print("我是用輪胎在奔馳");
    }
}

這種方式的設計铸董,一開始在小標題中已經說明了祟印,這是一種不好的實現方式。

將不確定的方法都寫成abstract粟害。然后由子類一個一個去實現蕴忆。子類按理說,可以擴展成任何形式的多功能步兵車我磁。完全可以滿足要求孽文。
的確驻襟,這是一種實現方式夺艰,可以滿足要求。但是沉衣,它不是一種好的實現方式郁副。
為什么說這種方式不好呢?

  1. 代碼不復用:如果現在有十輛車子豌习,五輛的攻擊方式一樣存谎,五輛的移動方式一樣。按照這種方式肥隆,每輛車都必須單獨實現自己的攻擊方式和移動方式既荚。那些相同的代碼無法做到復用。后期變更需求時栋艳,會面臨著海量的工作恰聘。
  2. 不靈活:利用繼承設計子類的行為,是在編譯的時候靜態(tài)決定了。如果在運行過程中晴叨,能夠動態(tài)的對子類進行擴展或改動凿宾,這樣最好不過了。
  3. 等等...

設計原則:

  • 找出可能需要變化之處兼蕊,把他們獨立出來
    *如果每次新需求一來初厚,這里代碼就要發(fā)生變化,那么這部分代碼就需要被抽出來孙技。
    把變化的抽取出來产禾,并做封裝。以便以后輕易的改動和擴充此部分 *
  • 針對接口編程牵啦,而不是針對實現編程
    針對接口編程的真正意義在于:利用編程語言多態(tài)的特性下愈,針對超類型編程(supertype)
public interface Animal {
}
public class Dog implements Animal{
}
// 實例化時不要使用Dog dog= new Dog();
Animal animal = new Dog();
// 更棒的是蕾久,可以將這個封裝成這樣
// 在運行時才指定具體的實現類
Animal animal = getAnimal();
  • 多用組合势似,少用繼承
    “有一個” 可能比 “是一個” 更好。
    使用繼承設計子類的行為僧著,是在編譯的時候靜態(tài)決定了履因,靈活度受到很大限制,所以我們要多用組合來替代繼承盹愚。
    例如現在有一個 Flyable 接口栅迄,你將一個Bird類實現這個Flyable接口以實現你想要的飛行功能。不如將Flyable接口作為Bird類的一個成員變量皆怕,以類似這種的方式將兩個類組合起來毅舆,這樣的程序更加靈活,彈性更大

(參考:Head Firsts設計模式)

策略模式設計

好了愈腾,按照上面的三條設計原則憋活,我們將整個程序的結構做一次調整。

  1. 將變化的部分提取出來虱黄,單獨封裝悦即。
    attack()move()會隨著子類不同而有所改變。將這兩個方法提取出來單獨封裝橱乱。
    type()作為子類共有的屬性和方法辜梳,就直接由子類繼承實現就好。
  2. 使用接口編程來替代現實編程泳叠。
    增加兩個接口:移動方式接口MoveBehavior 和 攻擊方式接口 AttackBehavior
  3. 使用組合來替代繼承作瞄。
    將移動方式接口MoveBehavior 和 攻擊方式接口 AttackBehavior作為多功能步兵車的成員變量。而不是直接由多功能步兵車繼承這兩個接口危纫。

多功能步兵車設計如下:

多功能步兵車類圖

攻擊方式接口設計如下:

攻擊方式

移動方式接口設計如下:

移動方式

代碼實現

首先定義兩種行為的接口:
public interface MoveBehavior {
    void move(); // 車輛的移動
}
public interface AttackBehavior {
    void attack(); // 武器的攻擊
}
再定義 多功能步兵車 這個基類類
public abstract class 多功能步兵車 {

    AttackBehavior attackBehavior;  // 車輛攻擊方式
    MoveBehavior moveBehavior;  // 車輛移動方式

    // 步兵車類型宗挥,由子類實現這個共有方法
    public abstract void type();

    // 開始攻擊
    public void attack() {
        attackBehavior.attack();
    }

    // 開始移動
    public void move() {
        moveBehavior.move();
    }

    // 設置攻擊方式
    public void setAttackBehavior(AttackBehavior behavior) {
        attackBehavior = behavior;
    }

    // 設置移動方式
    public void setMoveBehavior(MoveBehavior behavior) {
        moveBehavior = behavior;
    }
}

目前為止节预,基礎規(guī)則都設定完畢,下面就開始按照規(guī)則創(chuàng)造車輛的攻擊方式車輛的移動方式属韧。這里我們創(chuàng)建兩種武器和兩種移動方式:火箭攻擊機槍攻擊 安拟、輪子移動履帶移動

移動方式實現類
public class 輪胎移動 implements MoveBehavior {
    @Override
    public void move() {
        System.out.print("我是用輪胎在奔馳");
    }
}
public class 履帶移動 implements MoveBehavior {
    @Override
    public void move() {
        System.out.print("我是在用履帶奔馳");
    }
}
攻擊方式實現類
public class 火箭攻擊 implements AttackBehavior {
    @Override
    public void attack() {
        System.out.print("我用火箭打死你");
    }
}
public class 機槍攻擊 implements AttackBehavior {
    @Override
    public void attack() {
        System.out.print("我用機槍打死你");
    }
}

好了,現在說明都準備完畢了宵喂。
接下來讓我們來組裝真正的多功能步兵車糠赦。

1、火箭_履帶步兵車
public class 火箭_履帶步兵車 extends 多功能步兵車 {
    public 火箭_履帶步兵車(){ // 構造函數時锅棕,初始化武器了移動方式
        attackBehavior = new 火箭攻擊();
        moveBehavior = new 履帶移動();
    }
    @Override
    public void type() {
        System.out.print("我是火箭—履帶—步兵車");
    }
}
2拙泽、機槍_輪胎步兵車
public class 機槍_輪胎步兵車 extends 多功能步兵車 {
    public 機槍_輪胎步兵車(){ // 構造函數時,初始化武器了移動方式
        attackBehavior = new 機槍攻擊();
        moveBehavior = new 輪胎移動();
    }
    @Override
    public void type() {
        System.out.print("我是機槍—輪胎—步兵車");
    }
}

現在我們有了兩個定制性很強的步兵車了裸燎。
將相同的移動方式或者相同的攻擊方式也提取出來顾瞻,進行了復用。

而且德绿,這時使用組合的優(yōu)勢就體現出來了荷荤。
我們在多功能步兵車類中預留了兩個方法:

// 設置攻擊行為
public void setAttackBehavior(AttackBehavior behavior) {
     attackBehavior = behavior;
}

// 設置移動方式
public void setMoveBehavior(MoveBehavior behavior) {
    moveBehavior = behavior;
}

即使是在機槍_輪胎步兵車或者火箭_履帶步兵車已經實例化完成后,
你也可以調用上面的兩個方法移稳,隨時改變他的移動方式和攻擊方式蕴纳。
如果將多功能步兵車直接實現接口MoveBehaviorAttackBehavior,會很難有這樣靈活的變動个粱。

策略模式定義

看完了上面的一大坨東西古毛,咱們再次來說說策略模式的定義吧。

策略模式(Strategy Pattern):定義了算法簇都许,分別封裝起來稻薇,讓他們之間可以相互替換,此模式讓算法的變化獨立于使用算法的客戶胶征。

看了一個例子和兩遍概念的定義塞椎,你是不是對這個設計模式有了一定的理解?

這篇筆記中還提到了一些設計原則弧烤,這些設計原則可不僅僅在策略模式中有用忱屑,在其他設計模式中蹬敲,或者你平時寫代碼時都有很大的幫助暇昂。請牢記他們。(.)

第一篇筆記就寫到這里吧伴嗡!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末急波,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子瘪校,更是在濱河造成了極大的恐慌澄暮,老刑警劉巖名段,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異泣懊,居然都是意外死亡伸辟,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門馍刮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來信夫,“玉大人,你說我怎么就攤上這事卡啰【驳荆” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵匈辱,是天一觀的道長振湾。 經常有香客問我,道長亡脸,這世上最難降的妖魔是什么押搪? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮浅碾,結果婚禮上嵌言,老公的妹妹穿的比我還像新娘。我一直安慰自己及穗,他們只是感情好摧茴,可當我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布店量。 她就那樣靜靜地躺著鞭衩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪退客。 梳的紋絲不亂的頭發(fā)上焚虱,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天购裙,我揣著相機與錄音,去河邊找鬼鹃栽。 笑死躏率,一個胖子當著我的面吹牛,可吹牛的內容都是我干的民鼓。 我是一名探鬼主播薇芝,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼丰嘉!你這毒婦竟也來了夯到?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤饮亏,失蹤者是張志新(化名)和其女友劉穎耍贾,沒想到半個月后阅爽,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡荐开,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年付翁,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晃听。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡胆敞,死狀恐怖,靈堂內的尸體忽然破棺而出杂伟,到底是詐尸還是另有隱情移层,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布赫粥,位于F島的核電站观话,受9級特大地震影響,放射性物質發(fā)生泄漏越平。R本人自食惡果不足惜频蛔,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望秦叛。 院中可真熱鬧晦溪,春花似錦、人聲如沸挣跋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽避咆。三九已至舟肉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間查库,已是汗流浹背路媚。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留樊销,地道東北人整慎。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像围苫,于是被迫代替她去往敵國和親裤园。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,510評論 25 707
  • 設計模式基本原則 開放-封閉原則(OCP)够吩,是說軟件實體(類比然、模塊、函數等等)應該可以拓展周循,但是不可修改强法。開-閉原...
    西山薄涼閱讀 3,753評論 3 13
  • title: 設計模式簡介categories: 設計模式tags: 設計模式date: 2017-05-03 0...
    九命丿相柳閱讀 581評論 0 0
  • 設計模式六大原則 設計模式六大原則(1):單一職責原則 定義:不要存在多于一個導致類變更的原因。通俗的說湾笛,即一個類...
    viva158閱讀 763評論 0 1
  • 莫名的愛上你 走過你的身邊 繁花落了一地 綠葉飄滿天空 正如我的悠思 凝結在了大地
    慕言澈閱讀 273評論 1 5