一、策略模式——經典的“鴨子”行爲問題
1、定義:策略模式定義了算法族,分別封裝起來,讓他們之間可以互相替換,此模式讓算法的變化獨立於使用算法的客戶
涉及設計原則:
- 針對接口編程,而不是針對實現編程
- 找代碼中變化的地方並把他們獨立出來與不變的代碼區分開
核心:運用類的多態性 實現了超類引用對其所有子類的管理(向上轉型) 而子類的動作則是專門有行爲接口去規定 子類的具體行爲由動作接口實現去描述 最後超類和接口進行"組合" 實現了各個子類動作的真正區分
下面圖片 均來自headfirst 設計模式一書 源碼自己寫的
鴨子游戲問題:
模擬鴨子活動,有各種鴨子 會游泳、會飛、會叫
圖解:
選擇鴨子作爲一個超類 所有的鴨子都必須繼承它
但是這樣會導致各種各樣的問題
- 有的鴨子不會飛
- 有的鴨子不會叫
所以我們不能一味的繼承 而是需要另一種方法 去實現
從上面我們知道了 鴨子都能游泳 但是有的鴨子卻不會叫,有的鴨子能飛!所以我們需要在鴨子的超類上保留游泳動作,而會叫和能飛這兩個動作就被提取出去了 但是接下來又該怎麼辦呢?
解決:
將超類的飛 和叫 兩個動作提取出去 當做接口使用 面向接口化編程 即把 fly 和 quack 不確定的方法抽取出去 封裝在 一個飛動作接口 和 叫動作接口 下面是具體實現
整合鴨子的行爲 所有的動作接口變量都在超類duck中 由超類控制公共方法 實現類某個方法實現接口變量 下面是具體做法
具體代碼:
* @description 超類
**/
public abstract class Duck {
public FlyBehavior flyBehavior;
public QuckBehavior quckBehavior;
public void quck(){
quckBehavior.quck();
}
public void fly(){
flyBehavior.fly();
}
public void swimming(){
System.out.println("鴨子都會游泳!");
}
}
"飛"行爲接口
public interface FlyBehavior {
/**
* 飛
*/
void fly();
}
"叫"行爲接口
public interface QuckBehavior {
/**
* 叫
*/
void quck();
}
會飛鴨子動作具體實現
public class CanFlyImpl implements FlyBehavior {
@Override
public void fly() {
System.out.println("這隻鴨子會飛");
}
}
會叫鴨子動作具體實現
public class CanQuckImpl implements QuckBehavior {
@Override
public void quck() {
System.out.println("這隻鴨子會叫");
}
}
不會飛鴨子動作具體實現
public class NoWayFlyImpl implements FlyBehavior {
@Override
public void fly() {
System.out.println("這隻鴨子不會飛");
}
}
不會叫鴨子動作具體實現
public class NoWayQuckImpl implements QuckBehavior {
@Override
public void quck() {
System.out.println("這隻鴨子不會叫");
}
}
會飛的鴨子實體類
* @description 會飛的鴨子
**/
public class CanFlyDuck extends Duck {
public CanFlyDuck() {
//具體實現動作接口
this.flyBehavior = new CanFlyImpl();
this.quckBehavior = new NoWayQuckImpl();
}
public void display(){
System.out.println("會飛的鴨子卻不會叫");
}
}
會叫的鴨子實體類
* @description 會叫的鴨子
**/
public class CanQuckDuck extends Duck {
public CanQuckDuck() {
//具體實現動作接口
this.flyBehavior = new CanFlyImpl();
this.quckBehavior = new NoWayQuckImpl();
}
public void display(){
System.out.println("會飛的鴨子卻不會叫");
}
}
測試:
/**
* 策略模式
*/
Duck duck = new CanFlyDuck();
((CanFlyDuck) duck).display();
duck.fly();
duck.quck();
Duck duck1 = new CanQuckDuck();
((CanQuckDuck) duck1).display();
duck1.quck();
duck1.fly();