文章目錄
1. 模式引入–鴨子項目
具體要求如下:
-
有各種鴨子(比如 野鴨、北京鴨、水鴨等, 鴨子有各種行爲,比如 叫、飛行等)
-
顯示鴨子的信息
2. 傳統方案解決鴨子問題
定義一個抽象類,其中實現了叫和飛的功能,顯示的方法設置爲抽象,交給子類實現
3. 傳統方式解決鴨子問題分析和解決方案
-
其它鴨子,都繼承了Duck類,所以fly讓所有子類都會飛了,這是不正確的
-
上面說的1 的問題,其實是繼承帶來的問題:對類的局部改動,尤其超類的局部改動,會影響其他部分。會有溢出效應
-
爲了改進1問題,我們可以通過覆蓋fly 方法來解決 => 覆蓋解決
-
問題又來了,如果我們有一個玩具鴨子ToyDuck, 這樣就需要ToyDuck去覆蓋Duck的所有實現的方法 => 解決思路 策略模式 (strategy pattern)
4. 策略模式基本介紹
-
策略模式(Strategy Pattern)中,定義算法族,分別封裝起來,讓他們之間可以互相替換,此模式讓算法的變化獨立於使用算法的客戶
-
這算法體現了幾個設計原則,第一、把變化的代碼從不變的代碼中分離出來;第二、針對接口編程而不是具體類(定義了策略接口);第三、多用組合/聚合,少用繼承(客戶通過組合方式使用策略)。
4.1 策略模式的原理類圖
4.2 說明
客戶context 有成員變量strategy或者其他的策略接口,至於需要使用到哪個策略,我們可以在構造器中指定.
5. 策略模式解決鴨子問題
UML類圖
Flyable.java
// 飛行的策略接口
public interface Flyable {
public void fly();
}
Quackable.java
// 叫聲的策略接口
public interface Quackable {
public void quack();
}
BadQuack.java
// 叫聲的具體策略
public class BadQuack implements Quackable{
@Override
public void quack() {
System.out.println("BadQuack");
}
}
BadFly.java
// 飛行的具體策略
public class BadFly implements Flyable{
@Override
public void fly() {
System.out.println("BadFly");
}
}
CantFly.java
// 飛行的具體策略
public class CantFly implements Flyable{
@Override
public void fly() {
System.out.println("CantFly");
}
}
CantQuack.java
// 叫聲的具體策略
public class CantQuack implements Quackable{
@Override
public void quack() {
System.out.println("CantQuack");
}
}
GoodFly.java
// 飛行的具體策略
public class GoodFly implements Flyable{
@Override
public void fly() {
System.out.println("GoodFly");
}
}
GoodQuack.java
// 叫聲的具體策略
public class GoodQuack implements Quackable{
@Override
public void quack() {
System.out.println("GoodQuack");
}
}
Duck.java
// 抽象鴨子類
public abstract class Duck {
protected Flyable flyable;
protected Quackable quackable;
public void setFlyable(Flyable flyable) {
this.flyable = flyable;
}
public void setQuackable(Quackable quackable) {
this.quackable = quackable;
}
public void fly() {
flyable.fly();
}
public void quack() {
quackable.quack();
}
public abstract void display();
}
RealDuck.java
// 具體鴨子類
public class RealDuck extends Duck {
public RealDuck() {
flyable = new BadFly();
quackable = new GoodQuack();
}
@Override
public void display() {
System.out.println("RealDuck");
}
}
FackDuck.java
// 具體鴨子類
public class FackDuck extends Duck {
public FackDuck() {
flyable = new CantFly();
quackable = new CantQuack();
}
@Override
public void display() {
System.out.println("FackDuck");
}
}
測試Main.java
public class Main {
public static void main(String[] args) {
RealDuck realDuck = new RealDuck();
realDuck.fly();
realDuck.quack();
System.out.println();
FackDuck fackDuck = new FackDuck();
fackDuck.fly();
fackDuck.quack();
}
}
輸出結果
6. 策略模式的注意事項和細節
-
策略模式的關鍵是:分析項目中變化部分與不變部分
-
策略模式的核心思想是:多用組合/聚合 少用繼承;用行爲類組合,而不是行爲的繼承。更有彈性
-
體現了“對修改關閉,對擴展開放”原則,客戶端增加行爲不用修改原有代碼,只要添加一種策略(或者行爲)即可,避免了使用多重轉移語句(if…else if…else)
-
提供了可以替換繼承關係的辦法: 策略模式將算法封裝在獨立的Strategy類中使得你可以獨立於其Context改變它,使它易於切換、易於理解、易於擴展
-
需要注意的是:每添加一個策略就要增加一個類,當策略過多是會導致類數目龐大