設計模式(二十三)——策略模式(Arrays源碼分析)

1 編寫鴨子項目,具體要求以下:

1) 有各類鴨子(好比 野鴨、北京鴨、水鴨等, 鴨子有各類行爲,好比 叫、飛行等)java

2) 顯示鴨子的信息算法

2 傳統方案解決鴨子問題的分析和代碼實現

1) 傳統的設計方案(類圖)編程

 

 

 2)代碼實現ide

package com.lin.strategy;

public abstract class Duck {

    public abstract void display();
    
    public void quack() {
        System.out.println("鴨子嘎嘎嘎嘎");
    }
    
    public void swimming() {
        System.out.println("鴨子會游泳");
    }
    
    public void fly() {
        System.out.println("鴨子會飛");
    }
}

 

package com.lin.strategy;

public class PekingDuck extends Duck {

    @Override
    public void display() {
        System.out.println("這是北京鴨");

    }
    
    // 北京鴨很差飛翔
    @Override
    public void fly() {
        System.out.println("北京鴨不會飛翔");
    }

}

 

package com.lin.strategy;

public class ToyDuck extends Duck {

    @Override
    public void display() {
        System.out.println("玩具鴨");

    }
    
    // 要重寫全部父類的方法
    public void quack() {
        System.out.println("鴨子不會嘎嘎嘎嘎");
    }
    
    public void swimming() {
        System.out.println("鴨子不會游泳");
    }
    
    public void fly() {
        System.out.println("鴨子不會飛");
    }

}

 

package com.lin.strategy;

public class WildDuck extends Duck{

    @Override
    public void display() {
        System.out.println("這是野鴨!");        
    }

}

3 傳統的方式實現的問題分析和解決方案

1) 其它鴨子,都繼承了 Duck 類,因此 fly 讓全部子類都會飛了,這是不正確的源碼分析

2) 上面說的 1 的問題,實際上是繼承帶來的問題:對類的局部改動,尤爲超類的局部改動,會影響其餘部分。會有溢出效應this

3) 爲了改進 1 問題,咱們能夠經過覆蓋 fly  方法來解決 => 覆蓋解決spa

4) 問題又來了,若是咱們有一個玩具鴨子 ToyDuck, 這樣就須要 ToyDuck 去覆蓋 Duck 的全部實現的方法 => 解決思路 - 策略模式 (strategy pattern)設計

4 策略模式基本介紹

1) 策略模式(Strategy Pattern)中,定義算法族(策略組),分別封裝起來,讓他們之間能夠互相替換,此模式讓算法的變化獨立於使用算法的客戶code

2) 這算法體現了幾個設計原則,第1、把變化的代碼從不變的代碼中分離出來;第2、針對接口編程而不是具體類(定義了策略接口);第3、多用組合/聚合,少用繼承(客戶經過組合方式使用策略)。對象

5 策略模式的原理類圖

 

 

 說明:從上圖能夠看到,客戶 context 有成員變量 strategy 或者其餘的策略接口

,至於須要使用到哪一個策略,咱們能夠在構造器中指定

策略模式解決鴨子問題

1) 應用實例要求

編寫程序完成前面的鴨子項目,要求使用策略模式

2) 思路分析(類圖)

策略模式:分別封裝行爲接口,實現算法族,超類裏放行爲接口對象,在子類裏具體設定行爲對象。原則就是: 分離變化部分,封裝接口,基於接口編程各類功能。此模式讓行爲的變化獨立於算法的使用者

 

 

 

 3)代碼實現

package com.lin.strategy.plus;

public abstract class Duck {

    // 策略接口
    public FlyBehavior flyBehavior;
    
    public abstract void display();
    
    public void quack() {
        System.out.println("鴨子嘎嘎嘎嘎");
    }
    
    public void swimming() {
        System.out.println("鴨子會游泳");
    }
    
    public void fly() {
        if(flyBehavior != null) {
            flyBehavior.fly();
        }
    }
    
    // 動態改變某個對象的行爲
    public void setFly(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }
}

 

package com.lin.strategy.plus;

public class WildDuck extends Duck{

    public WildDuck() {
        super.flyBehavior = new GoodFly();
    }
    
    @Override
    public void display() {
        System.out.println("這是野鴨!");        
    }

}

 

package com.lin.strategy.plus;

public class ToyDuck extends Duck {

    public ToyDuck() {
        flyBehavior = new NotFly();
    }
    
    @Override
    public void display() {
        System.out.println("玩具鴨");

    }
    
    // 要重寫全部父類的方法
    public void quack() {
        System.out.println("鴨子不會嘎嘎嘎嘎");
    }
    
    public void swimming() {
        System.out.println("鴨子不會游泳");
    }
    
    

}

 

package com.lin.strategy.plus;

public class PekingDuck extends Duck {

    public PekingDuck() {
        flyBehavior = new NotFly();
    }
    
    @Override
    public void display() {
        System.out.println("北京鴨!");

    }
    
    
    

}

 

package com.lin.strategy.plus;

public class GoodFly implements FlyBehavior{

    @Override
    public void fly() {
        System.out.println("飛翔技術十分好");
    }

}

class NotFly implements FlyBehavior{

    @Override
    public void fly() {
        System.out.println("不會飛翔");
    }

}

class BadFly implements FlyBehavior{

    @Override
    public void fly() {
        System.out.println("飛翔技術不好");
    }

}

 

package com.lin.strategy.plus;

public interface FlyBehavior {

    void fly();
}

 

package com.lin.strategy.plus;

public class Client {

    public static void main(String[] args) {
        
        PekingDuck pekingDuck = new PekingDuck();
        pekingDuck.fly();
        
        // 動態改變某個對象的行爲
        pekingDuck.setFly(new GoodFly());
        pekingDuck.fly();
    }
    
}

策略模式在 JDK-Arrays 應用的源碼分析

1) JDK  Arrays  Comparator 就使用了策略模式

2)說明:從上圖能夠看到,客戶 context 有成員變量 strategy 或者其餘的策略接口

3)代碼分析+模式角色分析

 

 

 

package com.lin.strategy.plus;

import java.util.Arrays;
import java.util.Comparator;

public class StrategyTest {

    public static void main(String[] args) {
        
        // 實現降序排序,返回-1 放左邊,1 放右邊,0 保持不變
        // 說 明
        // 1.  實現了 Comparator 接口(策略接口) , 匿名類 對象 new Comparator<Integer>(){..}
        // 2.  對象 new Comparator<Integer>(){..}  就是實現了 策略接口 的對象
        // 3. public int compare(Integer o1, Integer o2){} 指定具體的處理方式
        Integer[] data = {3,4,6,78,1,0,-91};
        Comparator<Integer> comparator = new Comparator<Integer>() {

            @Override
            public int compare(Integer o1, Integer o2) {
                if(o1<o2) {                // 降序,升序
                    return 1;
                } else {
                    return -1;
                }
            }
        };
        
        // 方式一
        Arrays.sort(data, comparator);
        System.out.println(Arrays.toString(data));
        
        // 方式二
        Integer[] data1 = {3,4,6,78,1,0,-91};
        Arrays.sort(data1, (var1, var2) -> { 
            if(var1.compareTo(var2) > 0) {
                return 1;
            } else {
                return -1;
            }
        });
        
        System.out.println(Arrays.toString(data1));
    }
}

策略模式的注意事項和細節

1) 策略模式的關鍵是:分析項目中變化部分與不變部分

2) 策略模式的核心思想是:多用組合/聚合 少用繼承;用行爲類組合,而不是行爲的繼承。更有彈性

3) 體現了「對修改關閉,對擴展開放」原則,客戶端增長行爲不用修改原有代碼,只要添加一種策略(或者行爲) 便可,避免了使用多重轉移語句(if..else if..else

4) 提供了能夠替換繼承關係的辦法: 策略模式將算法封裝在獨立的 Strategy 類中使得你能夠獨立於其 Context 改變它,使它易於切換、易於理解、易於擴展

5) 須要注意的是:每添加一個策略就要增長一個類,當策略過可能是會致使類數目龐,至於須要使用到哪一個策略,咱們能夠在構造器中指定

 

 

僅供參考,有錯誤還請指出!

有什麼想法,評論區留言,互相指教指教。 

以爲不錯的能夠點一下右邊的推薦喲!

祝你們牛年大吉大利,牛氣沖天!

相關文章
相關標籤/搜索