圖解Java設計模式之策略模式 編寫鴨子項目,具體要求如下 : 傳統方案解決鴨子問題的分析和代碼實現 傳統方式解決鴨子問題分析和解決方案 策略模式基本介紹 策略模式的原理類圖 策略模式解決鴨子問題 策略模式在JDK - Arrays 應用的源碼分析 策略模式的註意實現和細節 編寫鴨子項目,具體要求如 ...
圖解Java設計模式之策略模式
編寫鴨子項目,具體要求如下 :
1)有各種鴨子(比如 野鴨、北京鴨、水鴨等)鴨子有各種行為,比如叫、飛行等等。
2)顯示鴨子的信息
傳統方案解決鴨子問題的分析和代碼實現
1)傳統的設計方案(類圖)
package com.example.demo.dtrategy;
public abstract class Duck {
public Duck() {}
// 顯示鴨子信息
public abstract void display();
public void quack() {
System.out.println("鴨子嘎嘎叫~~~");
}
public void swim() {
System.out.println("鴨子會游泳~~~");
}
public void fly() {
System.out.println("鴨子會飛~~~");
}
}
package com.example.demo.dtrategy;
public class PekingDuck extends Duck {
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("~~ 北京鴨 ~~");
}
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println("北京鴨不能飛翔");
}
}
package com.example.demo.dtrategy;
public class ToyDuck extends Duck {
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("玩具鴨");
}
//需要重寫父類的所有方法
public void quack() {
System.out.println("玩具鴨不能叫~~");
}
public void swim() {
System.out.println("玩具鴨不會游泳~~");
}
public void fly() {
System.out.println("玩具鴨不會飛翔~~~");
}
}
package com.example.demo.dtrategy;
public class WildDuck extends Duck {
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println(" 這是野鴨 ");
}
}
傳統方式解決鴨子問題分析和解決方案
1)其它鴨子,都繼承類Duck類,所以fly讓所有子類都會飛類,這是不正確的。
2)上面說的1的問題,其實是繼承帶來的問題 :對類的局部改動,尤其超類的局部改動,會影響其它部分。會有溢出效應。
3)為了改進1問題,我們可以通過覆蓋fly 方法來解決 - 》覆蓋解決
4)問題又來來,如果我們有一個玩具鴨子ToyDuck,這樣就需要ToyDuck去覆蓋Duck的所有實現的方法 = 》策略模式(strategy pattern)
策略模式基本介紹
1)策略模式(Strategy Pattern)中,定義演算法族,分別封裝起來,讓他們之間可以相互替換,此模式讓演算法的變化獨立於使用演算法的客戶。
2)這演算法體現來幾個設計原則,第一、把變化的代碼從不變的代碼中分離出來;第二、針對介面編程而不是具體類(定義來策略介面):第三、多組合/聚合,少用繼承(客戶通過組合方式使用策略)。
策略模式的原理類圖
說明 :從上圖可以看到,客戶端context 有成員變數 strategy 或者其它的策略介面,至於需要使用到那個策略,我們可以在構造器中指定。
策略模式解決鴨子問題
1)應用實例要求
編寫程式完成前面的鴨子項目,要求使用策略模式
2)類圖
package com.example.demo.dtrategy.improe;
public interface FlyBehavior {
void fly(); // 子類具體實現
}
package com.example.demo.dtrategy.improe;
public interface QuackBehavior {
}
package com.example.demo.dtrategy.improe;
public class BadFlyBehavior implements FlyBehavior {
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println(" 飛翔技術一般 ");
}
}
package com.example.demo.dtrategy.improe;
public abstract class Duck {
//屬性, 策略介面
FlyBehavior flyBehavior;
//其它屬性<->策略介面
QuackBehavior quackBehavior;
public Duck() {}
// 顯示鴨子信息
public abstract void display();
public void quack() {
System.out.println("鴨子嘎嘎叫~~~");
}
public void swim() {
System.out.println("鴨子會游泳~~~");
}
public void fly() {
// 改進
if(flyBehavior != null) {
flyBehavior.fly();
}
}
public FlyBehavior getFlyBehavior() {
return flyBehavior;
}
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public QuackBehavior getQuackBehavior() {
return quackBehavior;
}
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
}
package com.example.demo.dtrategy.improe;
public class GoodFlyBehavior implements FlyBehavior {
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println(" 飛翔技術高超 ~~~");
}
}
package com.example.demo.dtrategy.improe;
public class NoFlyBehavior implements FlyBehavior {
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println(" 不會飛翔 ");
}
}
package com.example.demo.dtrategy.improe;
public class PekingDuck extends Duck {
//假如北京鴨可以飛翔,但是飛翔技術一般
public PekingDuck() {
// TODO Auto-generated constructor stub
flyBehavior = new BadFlyBehavior();
}
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("~~北京鴨~~~");
}
}
package com.example.demo.dtrategy.improe;
public class ToyDuck extends Duck {
public ToyDuck() {
// TODO Auto-generated constructor stub
flyBehavior = new NoFlyBehavior();
}
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("玩具鴨");
}
//需要重寫父類的所有方法
public void quack() {
System.out.println("玩具鴨不能叫~~");
}
public void swim() {
System.out.println("玩具鴨不會游泳~~");
}
}
package com.example.demo.dtrategy.improe;
public class WilDuck extends Duck {
/**
* 構造器,傳入FlyBehavor 的對象
*/
public WilDuck() {
flyBehavior = new GoodFlyBehavior();
}
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println(" 這是野鴨 ");
}
}
package com.example.demo.dtrategy.improe;
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
WilDuck wildDuck = new WilDuck();
wildDuck.fly();//
ToyDuck toyDuck = new ToyDuck();
toyDuck.fly();
PekingDuck pekingDuck = new PekingDuck();
pekingDuck.fly();
//動態改變某個對象的行為, 北京鴨 不能飛
pekingDuck.setFlyBehavior(new NoFlyBehavior());
System.out.println("北京鴨的實際飛翔能力");
}
}
策略模式在JDK - Arrays 應用的源碼分析
說明:
- 實現了 Comparator 介面(策略介面) , 匿名類 對象 new Comparator(){…}
- 對象 new Comparator(){…} 就是實現了 策略介面 的對象
- public int compare(Integer o1, Integer o2){} 指定具體的處理方式
策略模式的註意實現和細節
1)策略模式的關鍵是 :分析項目中變化部分與不變部分
2)策略模式的核心思想是 :多用組合/聚合,少用繼承;用行為類組合,而不是行為的繼承。更有彈性。
3)體現了“開閉原則”。客戶端增加行為不用修改原有代碼,只要添加一種策略(或者行為)即可,避免了使用多重轉移語句(if…else if … else);
4)提供了可以替換繼承關心的辦法 :策略模式將演算法封裝在獨立的Strategy類中使得你可以獨立於其Context改變它,使它易於切換、易於理解、易於擴展。
5)需要註意的是 :每添加一個策略就要增加一個類,當策略過多是會導致類數目龐大。