最近在看設計模式的書籍雷滚,將看到的知識做一個筆記需曾,方便記憶。
這是第一篇。
簡介
設計模式(Design pattern)代表了最佳的實踐呆万。設計模式是開發(fā)人員面臨問題的解決方案商源。這些解決方案是眾多開發(fā)人員經過相當長的一段時間試驗和總結出來的。
什么是策略設計模式
策略模式(Strategy Pattern):定義了算法簇谋减,分別封裝起來牡彻,讓他們之間可以相互替換,此模式讓算法的變化獨立于使用算法的客戶出爹。
... 好吧庄吼,太拗口了。
還是直接看例子吧严就。
場景:
現在有這樣一個需求:現在需要用代碼設計一輛多功能步兵車
总寻。
要求如下:
- 這個車輛必須可以裝載不同的武器,實現不同的攻擊方式梢为。
- 這個車可以安裝不同的輪子渐行,實現不同的移動方式。
一種不好的實現方式
代碼實現:
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
粟害。然后由子類一個一個去實現蕴忆。子類按理說,可以擴展成任何形式的多功能步兵車
我磁。完全可以滿足要求孽文。
的確驻襟,這是一種實現方式夺艰,可以滿足要求。但是沉衣,它不是一種好的實現方式郁副。
為什么說這種方式不好呢?
-
代碼不復用
:如果現在有十輛車子豌习,五輛的攻擊方式一樣存谎,五輛的移動方式一樣。按照這種方式肥隆,每輛車都必須單獨實現自己的攻擊方式和移動方式既荚。那些相同的代碼無法做到復用。后期變更需求時栋艳,會面臨著海量的工作恰聘。 -
不靈活
:利用繼承設計子類的行為,是在編譯的時候靜態(tài)決定了。如果在運行過程中晴叨,能夠動態(tài)的對子類進行擴展或改動凿宾,這樣最好不過了。 - 等等...
設計原則:
-
找出可能需要變化之處兼蕊,把他們獨立出來
*如果每次新需求一來初厚,這里代碼就要發(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設計模式)
策略模式設計
好了愈腾,按照上面的三條設計原則憋活,我們將整個程序的結構做一次調整。
- 將變化的部分提取出來虱黄,單獨封裝悦即。
attack()
和move()
會隨著子類不同而有所改變。將這兩個方法提取出來單獨封裝橱乱。
type()
作為子類共有的屬性和方法辜梳,就直接由子類繼承實現就好。 - 使用接口編程來替代現實編程泳叠。
增加兩個接口:移動方式接口MoveBehavior
和 攻擊方式接口AttackBehavior
- 使用組合來替代繼承作瞄。
將移動方式接口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;
}
即使是在機槍_輪胎步兵車
或者火箭_履帶步兵車
已經實例化完成后,
你也可以調用上面的兩個方法移稳,隨時改變他的移動方式和攻擊方式蕴纳。
如果將多功能步兵車
直接實現接口MoveBehavior
和AttackBehavior
,會很難有這樣靈活的變動个粱。
策略模式定義
看完了上面的一大坨東西古毛,咱們再次來說說策略模式的定義吧。
策略模式(Strategy Pattern):定義了算法簇都许,分別封裝起來稻薇,讓他們之間可以相互替換,此模式讓算法的變化獨立于使用算法的客戶胶征。
看了一個例子和兩遍概念的定義塞椎,你是不是對這個設計模式有了一定的理解?
這篇筆記中還提到了一些設計原則弧烤,這些設計原則可不僅僅在策略模式中有用忱屑,在其他設計模式中蹬敲,或者你平時寫代碼時都有很大的幫助暇昂。請牢記他們。(.)
第一篇筆記就寫到這里吧伴嗡!