Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> java/android 設計模式學習筆記(17)---策略模式

java/android 設計模式學習筆記(17)---策略模式

編輯:關於Android編程

這篇博客我們來介紹一下策略模式(Strategy Pattern,或者叫 Policy Pattern),也是行為型模式之一。通常在軟件開發中,我們為了一個功能可能會設計多種算法和策略,然後根據實際使用情況動態選擇對應的算法和策略,比如排序算法中的快速排序,冒泡排序等等,根據時間和空間的綜合考慮進行運行時選擇。
  針對這種情況,一個常規的方法是將多種算法寫在一個類中,每一個方法對應一個具體的排序算法,或者寫在一個方法中,通過 if…else 或者 switch…case 條件來選擇具體的排序算法。這兩種方法我們都成為硬編碼,雖然很簡單,但是隨著算法數量的增加,這個類就會變得越來越臃腫,維護的成本就會變高,修改一處容易導致其他地方的錯誤,增加一種算法就需要修改封裝算法類的源代碼,即違背了開閉原則和單一職責原則。
  如果將這些算法或者策略抽象出來,提供一個統一的接口,不同的算法或者策略有不同的實現類,這樣在程序客戶端就可以通過注入不同的實現對象來實現算法或者策略的動態替換,這種模式的可擴展性、可維護性也就更高,這就是下面講到的策略模式。

特點

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

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

 

UML類圖

我們來看看策略模式的 uml 類圖:
  這裡寫圖片描述vcfJq6O6PC9wPg0KQ29udGV4dKO608PAtLLZ1/ey38LUtcTJz8/CzsS7t76zo7tTdHJhZ2V0eaO6st/C1LXEs+nP86O7Q29uY3JldGVTdHJhdGVneaO6vt/M5bXEst/C1Mq1z9aho6GhoaG+3bTLztLDx7/J0tTQtLP2st/C1MSjyr21xM2o08O0+sLro7o8YnIgLz4NCjxzdHJvbmc+U3RyYWdldHkuY2xhc3M8L3N0cm9uZz4NCjxwPiZuYnNwOzwvcD4NCjxwcmUgY2xhc3M9"brush:java;"> public interface Stragety { void algorithm(); }

ConcreteStragetyA.class 和 ConcreteStragetyB.class

public class ConcreteStragetyA implements Stragety{
    @Override
    public void algorithm() {
        System.out.print("ConcreteStragetyA\n");
    }
}
public class ConcreteStragetyB implements Stragety{
    @Override
    public void algorithm() {
        System.out.print("ConcreteStragetyB\n");
    }
}

默認策略類ConcreteStragetyDefault.class

public class ConcreteStragetyDefault implements Stragety{
    @Override
    public void algorithm() {
        System.out.print("null stragety");
    }
}

Context.class 和測試代碼

public class Context {

    private Stragety stragety;

    public Context() {
        stragety = new ConcreteStragetyDefault();
    }

    public void algorithm() {
        stragety.algorithm();
    }

    public void setStragety(Stragety stragety) {
        if (stragety == null) {
            throw new IllegalArgumentException("argument must not be null!!!");
        }
        this.stragety = stragety;
    }

    public static void main(String args[]) {
        Context context = new Context();
        context.setStragety(new ConcreteStragetyA());
        context.algorithm();
        context.setStragety(new ConcreteStragetyB());
        context.algorithm();
    }
}

代碼很簡單,一目了然,沒有if-else,沒有 switch-case。核心就是建立抽象,將不同的策略構建成一個個具體的策略實現,通過不同的策略實現算法替換,在簡化邏輯、結構的同時,增強系統的可讀性、穩定性和可擴展性,這對於較為復雜的業務邏輯顯得更為直觀,擴展也更加方便。

示例與源碼

Android 源碼中策略模式

其實在 Android 源碼中策略模式使用的次數也是很多,大家常見的動畫中就有使用到策略模式:

public abstract class Animation implements Cloneable {
    /**
     * The interpolator used by the animation to smooth the movement.
     */
    Interpolator mInterpolator;
    ....
    /**
     * Sets the acceleration curve for this animation. Defaults to a linear
     * interpolation.
     *
     * @param i The interpolator which defines the acceleration curve
     * @attr ref android.R.styleable#Animation_interpolator
     */
    public void setInterpolator(Interpolator i) {
        mInterpolator = i;
    }
    ....
    /**
     * Gets the transformation to apply at a specified point in time. Implementations of this
     * method should always replace the specified Transformation or document they are doing
     * otherwise.
     *
     * @param currentTime Where we are in the animation. This is wall clock time.
     * @param outTransformation A transformation object that is provided by the
     *        caller and will be filled in by the animation.
     * @return True if the animation is still running
     */
    public boolean getTransformation(long currentTime, Transformation outTransformation) {
        ......

            final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
            applyTransformation(interpolatedTime, outTransformation);
        ......
    }
}

Animation 類就是很典型用到策略模式的類,它裡面會有一個 Interpolator 插值器對象,用來在執行動畫的時候達到所需要的速度變化效果,系統提供的插值器有 LinearInterpolator(線性插值器,動畫的執行速度相等),AccelerateDecelerateInterpolator (加速減速插值器,動畫的執行起始加速,結尾減速),DecelerateInterpolator(減速插值器,速度隨著動畫的執行變慢),以及回彈插值器等等,感興趣的上網查閱一下相關資料即可。

wiki example

這裡我就仍然以 wiki 上的代碼為例,商場在不同時段會有打折促銷活動,顧客在不同的時段分別進行購買,最後得出一個價格:
BillingStragety.class

interface BillingStrategy {
    public double getActPrice(double rawPrice);
}

NormalStrategy.class 和 HappyHourStragety.class

// Normal billing strategy (unchanged price)
class NormalStrategy implements BillingStrategy {
    @Override
    public double getActPrice(double rawPrice) {
        return rawPrice;
    }
}
// Strategy for Happy hour (50% discount)
class HappyHourStrategy implements BillingStrategy {
    @Override
    public double getActPrice(double rawPrice) {
        return rawPrice * 0.5;
    }

}

Customer.class

class Customer {

    private List drinks;
    private BillingStrategy strategy;

    public Customer(BillingStrategy strategy) {
        this.drinks = new ArrayList();
        this.strategy = strategy;
    }

    public void add(double price, int quantity) {
        drinks.add(strategy.getActPrice(price * quantity));
    }

    // Payment of bill
    public void printBill() {
        double sum = 0;
        for (Double i : drinks) {
            sum += i;
        }
        System.out.println("Total due: " + sum);
        drinks.clear();
    }

    // Set Strategy
    public void setStrategy(BillingStrategy strategy) {
        this.strategy = strategy;
    }

}

main

public class StrategyPatternWiki {

    public static void main(String[] args) {
        Customer firstCustomer = new Customer(new NormalStrategy());

        // Normal billing
        firstCustomer.add(1.0, 1);

        // Start Happy Hour
        firstCustomer.setStrategy(new HappyHourStrategy());
        firstCustomer.add(1.0, 2);

        // New Customer
        Customer secondCustomer = new Customer(new HappyHourStrategy());
        secondCustomer.add(0.8, 1);
        // The Customer pays
        firstCustomer.printBill();

        // End Happy Hour
        secondCustomer.setStrategy(new NormalStrategy());
        secondCustomer.add(1.3, 2);
        secondCustomer.add(2.5, 1);
        secondCustomer.printBill();

    }
}

不同時段買的東西,最後得出一個價錢,多種算法動態切換,用戶不用去關心具體的內部細節。

總結

策略模式主要是用來分離算法,在相同的行為抽象下有不同的具體實現策略。這個模式很好的演示了開閉原則:定義抽象,增加新的策略只需要增加新的類,然後在運行中動態更換即可,沒有影響到原來的邏輯,從而達到了很好的可擴展性。
  優點:

結構清晰明了、使用簡單直觀;耦合度相對而言較低,擴展方便;操作封裝也更為徹底,數據更為安全。  缺點也很明顯,這當然也是很多設計模式的通病:類的增多,隨著策略的增加,子類也會變得繁多。

源碼下載

https://github.com/zhaozepeng/Design-Patterns/tree/master/StrategyPattern

 
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved