時勢造英雄——策略模式

HunterArley發表於2019-01-24

《Android原始碼設計模式解析與實戰》讀書筆記(七)

《Android原始碼設計模式解析與實戰》PDF資料下載

一、策略模式的簡介

1.1、定義

策略模式定義了一系列的演算法,並將每一個演算法封裝起來,而且使它們還可以相互替換。策略模式讓演算法獨立於使用它的客戶而獨立變化。

1.2、使用場景

  • 針對同一型別問題的多種處理方式,僅僅是具體行為有差別時;
  • 需要安全地封裝多種同一型別的操作時。
  • 出現同一抽象類有多個子類,而又需要使用if-else或者switch-case來選擇具體子類時。

二、策略模式的簡單實現

示例:公交車和地鐵的價格計算方式是不一樣的,需要計算乘不同出行工具的成本,下面是第一版的程式碼:

public class PriceCalculator {
    //公交車型別
    private static final int BUS = 1;
    //地鐵型別
    private static final int SUBWAY = 2;

    public static void main(String[] args) {
        PriceCalculator calculator = new PriceCalculator();
        System.out.println("坐16公里的公交車票價為:" + calculator.calculatePrice(16, BUS));
        System.out.println("坐16公里的地鐵票價為:" + calculator.calculatePrice(16, SUBWAY));
    }

    /**
     * 北京公交車,十公里之內一元錢,超過十公里之後每加一元錢可以乘5公里
     *
     * @param km
     * @return
     */
    private int busPrice(int km) {
        //超過十公里的總距離
        int extraTotal = km - 10;
        //超過的距離是5公里的倍數
        int extraFactor = extraTotal / 5;
        //超過的距離對5公里取餘
        int fraction = extraTotal % 5;
        //價格計算
        int price = 1 + extraFactor * 1;
        return fraction > 0 ? ++price : price;
    }

    /**
     * 6公里(含)內3元;6~12公里(含)4元;12~22公里(含)5元;22~32公里(含)6元;
     * @param km
     * @return
     */
    private int subwayPrice(int km) {
        if (km <= 6) {
            return 3;
        } else if (km > 6 && km <= 12) {
            return 4;
        } else if (km > 12 && km <= 22) {
            return 5;
        } else if (km > 22 && km <= 32) {
            return 6;
        }
        return 7;
    }

    int calculatePrice(int km, int type) {
        if (type == BUS) {
            return busPrice(km);
        } else if (type == SUBWAY) {
            return subwayPrice(km);
        }
        return 0;
    }
}
複製程式碼

輸出結果:

策略模式1.png

此時的程式碼已經比較混亂,各種if-else語句纏繞其中。當價格的計算方法變化時,需要直接修改這個類中的程式碼,很容易引入錯誤。 這類程式碼必然是難以應對變化的,它會使得程式碼變得越來越臃腫,難以維護。

用策略模式對上述示例進行重構:

/**
 * 計算介面
 */
public interface CalculateStrategy {
    /**
     * 按距離來計算價格
     * @param km
     * @return
     */
    int calculatePrice(int km);
}
複製程式碼
//公交車價格計算策略
public class BusStrategy implements CalculateStrategy {
    /**
     * 北京公交車,十公里之內一元錢,超過十公里之後每加一元錢可以乘5公里
     * @param km
     * @return
     */
    @Override
    public int calculatePrice(int km) {
        //超過十公里的總距離
        int extraTotal = km - 10;
        //超過的距離是5公里的倍數
        int extraFactor = extraTotal / 5;
        //超過的距離對5公里取餘
        int fraction = extraTotal % 5;
        //價格計算
        int price = 1 + extraFactor * 1;
        return fraction > 0 ? ++price : price;
    }
}
複製程式碼
public class SubwayStrategy implements CalculateStrategy {
    @Override
    public int calculatePrice(int km) {
        if (km <= 6) {
            return 3;
        } else if (km > 6 && km <= 12) {
            return 4;
        } else if (km > 12 && km <= 22) {
            return 5;
        } else if (km > 22 && km <= 32) {
            return 6;
        }
        return 7;
    }
}
複製程式碼

再建立一個扮演Context角色的類

public class TranficCalculator {
    public static void main(String[] args) {
        TranficCalculator calculator = new TranficCalculator();
        //設定計算策略
        calculator.setStrategy(new BusStrategy());
        //計算價格
        System.out.println("坐16公里的公交車票價為:"+calculator.calculatePrice(16));
    }

    CalculateStrategy mStrategy;
    public void setStrategy(CalculateStrategy mStrategy) {
        this.mStrategy = mStrategy;
    }

    public int calculatePrice(int km) {
        return mStrategy.calculatePrice(km);
    }
}
複製程式碼

這種方案在隱藏實現的同時,可擴充套件性變得很強。在簡化邏輯、結構的同時,增強了系統的可讀性、穩定性、可擴充套件性,這對於較為複雜的業務邏輯顯得更為直觀,擴充套件也更為方便。

三、總結

策略模式主要用來分離演算法,在相同的行為抽象下有不同的具體實現策略。這個模式很好地演示了開閉原則,也就是定義抽象,注入不同的實現,從而達到很好的可擴充套件性。

3.1、優點

  1. 結構清晰明瞭、使用簡單直觀;
  2. 耦合度相對而言較低,擴充套件方便;
  3. 操作封裝也更為徹底,資料更為安全。

3.2、缺點

  1. 隨著策略的增加,子類也會變得繁多。

學海無涯苦作舟

我的微信公眾號

相關文章