策略模式其實特別簡單(聽到這句話,大家是不是心里一下子放松了?)。
比如排序,官方告訴大家我這里有一個排序的接口ISort的sort()方法,然后民間各盡其能,實現這個排序的方法:冒泡,快速,堆等等。
這些方法就是“不同的策略”。
然后,某個模塊下,需要一個排序方法,但是暫時不能指定具體的sort方法(出於擴展的考慮),就需要使用ISort接口了。
最后,具體什么場景下,傳入什么具體的sort方法,實現靈活的排序。
這就是策略模式!
下面,我們分析Android中的動畫是如何使用策略模式的。
1. 意圖
定義一系列的算法,把它們一個個封裝起來,並且使它們可互相替換。
策略模式使得算法可獨立於使用它的客戶而變化。
2. 結構圖和代碼
Animation不同動畫的實現,主要是依靠Interpolator的不同實現而變。
定義接口Interpolator:
package android.animation; /** * A time interpolator defines the rate of change of an animation. This allows animations * to have non-linear motion, such as acceleration and deceleration. */ public interface Interpolator { /** * Maps a value representing the elapsed fraction of an animation to a value that represents * the interpolated fraction. This interpolated value is then multiplied by the change in * value of an animation to derive the animated value at the current elapsed animation time. * * @param input A value between 0 and 1.0 indicating our current point * in the animation where 0 represents the start and 1.0 represents * the end * @return The interpolation value. This value can be more than 1.0 for * interpolators which overshoot their targets, or less than 0 for * interpolators that undershoot their targets. */ float getInterpolation(float input); }
我們以AccelerateInterpolator為例,實現具體的策略,代碼如下:
package android.view.animation; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; /** * An interpolator where the rate of change starts out slowly and * and then accelerates. * */ public class AccelerateInterpolator implements Interpolator { private final float mFactor; private final double mDoubleFactor; public AccelerateInterpolator() { mFactor = 1.0f; mDoubleFactor = 2.0; } /** * Constructor * * @param factor Degree to which the animation should be eased. Seting * factor to 1.0f produces a y=x^2 parabola. Increasing factor above * 1.0f exaggerates the ease-in effect (i.e., it starts even * slower and ends evens faster) */ public AccelerateInterpolator(float factor) { mFactor = factor; mDoubleFactor = 2 * mFactor; } public AccelerateInterpolator(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AccelerateInterpolator); mFactor = a.getFloat(com.android.internal.R.styleable.AccelerateInterpolator_factor, 1.0f); mDoubleFactor = 2 * mFactor; a.recycle(); } public float getInterpolation(float input) { if (mFactor == 1.0f) { return input * input; } else { return (float)Math.pow(input, mDoubleFactor); } } }
其他的Interpolator實現在此不列舉了。
如何在Animation模塊實現不同的動畫呢?
在這里我想提一個應用很廣的概念:依賴注入。
在Animation模塊里實現不同的動畫,就是需要我們把各個Interpolator以父類或者接口的形式注入進去。
注入的方法一般是構造函數,set方法,注釋等等。
我們看看animation類是怎么做的:
public abstract class Animation implements Cloneable { Interpolator mInterpolator; // 通過set方法注入 public void setInterpolator(Interpolator i) { mInterpolator = i; } public boolean getTransformation(long currentTime, Transformation outTransformation) { // ... ... // 具體調用 final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime); applyTransformation(interpolatedTime, outTransformation); // ... ... } // 缺省實現,是個小技巧,順便提下,這個不是重點 protected void ensureInterpolator() { if (mInterpolator == null) { mInterpolator = new AccelerateDecelerateInterpolator(); } } }
策略模式其實就是多態的一個淋漓精致的體現。
3. 效果
(1).行為型模式
(2).消除了一些if...else...的條件語句
(3).客戶可以對實現進行選擇,但是客戶必須要了解這個不同策略的實現(這句話好像是廢話,總而言之,客戶需要學習成本)
(4).代碼注釋中提到了缺省實現,可以讓客戶不了解策略,也能實現默認的策略
(5).注入的方式有多種:構造函數,set方法,注釋。配置解析等等