編輯:關於Android編程
這篇博客我們來介紹一下策略模式(Strategy Pattern,或者叫 Policy Pattern),也是行為型模式之一。通常在軟件開發中,我們為了一個功能可能會設計多種算法和策略,然後根據實際使用情況動態選擇對應的算法和策略,比如排序算法中的快速排序,冒泡排序等等,根據時間和空間的綜合考慮進行運行時選擇。
針對這種情況,一個常規的方法是將多種算法寫在一個類中,每一個方法對應一個具體的排序算法,或者寫在一個方法中,通過 if…else 或者 switch…case 條件來選擇具體的排序算法。這兩種方法我們都成為硬編碼,雖然很簡單,但是隨著算法數量的增加,這個類就會變得越來越臃腫,維護的成本就會變高,修改一處容易導致其他地方的錯誤,增加一種算法就需要修改封裝算法類的源代碼,即違背了開閉原則和單一職責原則。
如果將這些算法或者策略抽象出來,提供一個統一的接口,不同的算法或者策略有不同的實現類,這樣在程序客戶端就可以通過注入不同的實現對象來實現算法或者策略的動態替換,這種模式的可擴展性、可維護性也就更高,這就是下面講到的策略模式。
策略模式定義了一系列的算法,並將每一個算法封裝起來,而且使他們可以相互替換,讓算法獨立於使用它的客戶而獨立變化。
策略模式的使用場景:
我們來看看策略模式的 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 源碼中策略模式使用的次數也是很多,大家常見的動畫中就有使用到策略模式:
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 上的代碼為例,商場在不同時段會有打折促銷活動,顧客在不同的時段分別進行購買,最後得出一個價格:
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
Android RecyclerView打造自動循環效果
先看效果圖主要處理的地方:1、RecyclerView中Adapter的item個人可以無限輪詢.2、RecyclerView自動滑動3、手指按下時滑動停止,手指抬起後繼
Android View 事件分發機制源碼詳解(ViewGroup篇)
前言我們在學習View的時候,不可避免會遇到事件的分發,而往往遇到的很多滑動沖突的問題都是由於處理事件分發時不恰當所造成的。因此,深入了解View事件分發機制的原理,對於
Android中Service(後台服務)詳解
1.概念: (1).Service可以說是一個在後台運行的Activity。它不是一個單獨的進程,它只需要應用告訴它要在後台做什麼就可以了。 (2).它要是實現和用戶的交
Android使用Face++架構包實現人臉識別淺析
我們點開案例可以看到眾多我們熟知的軟件都是使用的這個公司所提供的SDK然後我們點擊開發者中心中的開發工具與sdk下載我們所需要的sdk之後再點擊我的應用中的創建應用之後他