博客新址,這裏更有趣android
目錄算法
策略模式app
爲何使用策略模式?函數
策略模式應用實例動畫
策略模式:創建行爲族,將不一樣的行爲分別封裝,同時彼此可相互替代,算法的變化能夠獨立於使用者。
優勢:提升了可複用性,將行爲和使用者解耦出來
缺點:增長了編寫代碼工做量this
經過一個遊戲的例子咱們能夠更好的說明這個問題,咱們的遊戲中有不少的人物,這個時候,咱們定義一個基礎遊戲角色類,而後不一樣的角色將會有不一樣的技能,因此其攻擊行爲和防護行爲在不一樣的角色中是不一樣的,其單位攻擊所形成的傷害和攻擊的特效也是不一樣的,若是按照傳統的方式,咱們首先想到的寫法多是這樣子的。設計
//基類,具備攻擊和防護行爲,全部遊戲角色繼承自這個基類 class People{ People(){ } //攻擊 public void attck(){ } //防護 public void defense(){ } } //法師角色 class Master extends People{ Master(){ } public void attck(){ 形成魔法傷害 } public void defense(){ 抵禦魔法攻擊 } } //劍客角色 class Swordsman extends People{ Swordsman(){ } public void attck(){ 形成物理傷害 } public void defense(){ 抵禦物理攻擊 } }
這樣子來看徹底可行,咱們須要什麼角色實例的時候只須要new一個便可,可是咱們的遊戲中的角色每每是有不少的,而不僅是簡單這幾種的。當咱們爲了改善遊戲體驗進一步吸引用戶,因此須要對遊戲中的角色的攻擊增長特效或者是對防護增長某種特殊防護,或者是該角色的攻擊方式和防護方式都發生了變化,這個時候咱們就須要對每個角色類進行查找,找到那些角色有這種攻擊方式和防護方式,而後打開對其進行修改,工做將變得很繁瑣,同時對原有的類進行修改也進一步增長了咱們犯錯的概率。如何改善這種情況呢?這個時候咱們須要考慮,這其中那些東西是變的,而那些東西是固定的,而後封裝變化的。這也正是設計的一個原則找出那些變化的將他們獨立出來,不要和那些不須要變化的混在一塊兒。code
因此咱們想到將這些變化的行爲,攻擊和防護進行封裝起來,將一些不會變化的好比,姓名,性別設置,更新方法與之孤立起來。將行爲進行封裝,便於咱們後期的需求變動時,對項目進行更新,那麼咱們想到的就是設置不一樣的行爲類,而後經過委託的方式,在角色的內部發生其真實行爲。那麼咱們能夠寫出下面的代碼。orm
abstract class People{ Attackable attckable; Denfenseable denfenseable; public void setAttckMethond(Attackable attckable){ this.attckable = attckable; } public void setDefenseMethond(Denfenseable denfenseable){ this.denfenseable = denfenseable; } public void attck(){ attckable.invoke(); } public void defense(){ denfenseable.invoke(); } public abstract void haveSex(); More Methond..... } //法師 class Master extends People{ Master(){ } public void haveSex(){ System.out.println("Come on"); } } //劍客 class Swordsman extends People{ Swordsman(){ } public void haveSex(){ System.out.println("ya mie die") } } //定義攻擊接口 public interface Attackable{ public void invoke(); } // 定義防護接口 public interface Denfenseable{ public void invoke(); } //實現了攻擊接口的秒殺全場攻擊 public class KillAll implements Attackable{ public void invoke(){ System.out.println("Kill All"); } } //實現了防護接口的抵禦任何攻擊接口 public class DenfenseAnyAttack implements Denfenseable{ public void invoke(){ System.out.println("Denfense All"); } }
將變化的攻擊和防護行爲單獨拿出來做爲接口,而後在基類中經過委託的形式,藉助多態,來實現相應的攻擊,防護方式,同時設置了set方法,使得其擴展性進一步加強。當咱們修改英雄的攻擊行爲和防護行爲只須要經過set方法便可,若是對攻擊和防護行爲的表現形式進行修改,經過找到相應的行爲類修改便可,藉助委託,多態,實現了完全的將對象和行爲進行解耦。對象
依賴注入:一般咱們能夠經過set方法,構造函數來將咱們所依賴的對象,經過接口或者是父類的形式注入進去。內部藉助委託機制實現相應的功能。
在咱們開法,咱們所使用的類庫中,有哪些是經過策略模式來實現的呢?
在Android的動畫中,Animation有一個方法爲setInterpolator() 熟悉Android開發的必定知道其做用,用來設置一個插值器,其做用是用來控制動畫開始結束等一些特效,而其實現就是使用了策略模式。
package android.animation; public interface Interpolator { float getInterpolation(float input); }
有一個插值器的接口,而後各類不一樣類型的插值器經過實現接口來實現不一樣的動畫特效。實現Interpolator接口的類有
AccelerateDecelerateInterpolator 在動畫開始與介紹的地方速率改變比較慢,在中間的時候加速
AccelerateInterpolator 在動畫開始的地方速率改變比較慢,而後開始加速
AnticipateInterpolator 開始的時候向後而後向前甩
AnticipateOvershootInterpolator 開始的時候向後而後向前甩必定值後返回最後的值
BounceInterpolator 動畫結束的時候彈起
CycleInterpolator 動畫循環播放特定的次數,速率改變沿着正弦曲線
DecelerateInterpolator 在動畫開始的地方快而後慢
LinearInterpolator 以常量速率改變
OvershootInterpolator 向前甩必定值後再回到原來位置
舉一個例子
package android.view.animation; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; public class AccelerateInterpolator implements Interpolator { private final float mFactor; private final double mDoubleFactor; public AccelerateInterpolator() { mFactor = 1.0f; mDoubleFactor = 2.0; } 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); } } }
Animation源碼
public abstract class Animation implements Cloneable { Interpolator mInterpolator; 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(); } } }
總結:經過對於源碼的分析,不難發現其和遊戲角色設定的類似之處,實現一個接口,而後不一樣行爲實現該接口,使用者經過set方法,以接口的形式,實現具體實例的依賴注入。從而實現相應的功能。