更多設計模式文章請閱讀:
1.定義:
定義一系列的算法,把每一個算法封裝起來, 並且使它們可相互替換。策略模式模式使得算法可獨立於使用它的客戶而獨立變化。
2.使用場景
-
意圖:定義一系列的算法,把它們一個個封裝起來, 並且使它們可相互替換。
-
主要解決:在有多種算法相似的情況下,使用 if…else 所帶來的複雜和難以維護。
-
何時使用:一個系統有許多許多類,而區分它們的只是他們直接的行爲。
-
如何解決:將這些算法封裝成一個一個的類,任意地替換。
-
關鍵代碼:實現同一個接口。
-
應用實例:
1、諸葛亮的錦囊妙計,每一個錦囊就是一個策略。
2、旅行的出遊方式,選擇騎自行車、坐汽車,或者自駕遊等每一種旅行方式都是一個策略。
3.UML建模圖
Context:用來操作策略的上下文環境。
Stragety:策略的抽象。
ConcreteStragetyA、ConcreteStragetyB:具體的策略實現。
4.策略模式的簡單實現
以選擇旅遊出行方式爲例,假如是2公里之內,則選擇自行車,如果是10公里之內,則選擇公交汽車,如果是10公里以外,則最好自駕車,比較的方便。
- 定義策略接口
public interface TravelWays {
/**
* 選擇交通工具
*/
void selectTransportation();
}
- 具體策略實現
分別定義三個策略來實現策略接口,用來分別對不同的距離的旅程選擇:
public class BicycleWay implements TravelWays {
@Override
public void selectTransportation() {
System.out.println("選擇了自行車出行方式");
}
}
public class BusWay implements TravelWays {
@Override
public void selectTransportation() {
System.out.println("選擇了公交出行");
}
}
public class CarWay implements TravelWays {
@Override
public void selectTransportation() {
System.out.println("選擇了自駕出行方式");
}
}
- 實現環境類
環境類的構造函數包含了策略類,通過傳進來不同的具體策略來調用不同策略的selectTransportation方法:
public class Context {
private TravelWays travelWays;
public Context(TravelWays travelWays) {
this.travelWays = travelWays;
}
public void selectTransportation(){
travelWays.selectTransportation();
}
}
- 客戶端調用
public class Client {
public static void main(String[] args) {
Context context;
//短途選擇自行車
TravelWays bicycle=new BicycleWay();
context=new Context(bicycle);
context.selectTransportation();
//中短途選擇公交
TravelWays bus=new BusWay();
context=new Context(bus);
context.selectTransportation();
//遠程選擇小汽車
TravelWays car=new CarWay();
context=new Context(car);
context.selectTransportation();
}
}
- 運行結果
5.優點缺點比較
優點
- 策略模式提供了管理相關的算法族的辦法。策略類的等級結構定義了一個算法或行爲族。恰當使用繼承可以把公共的代碼轉移到父類裏面,從而避免重複的代碼。
- 使用策略模式可以避免使用多重條件轉移語句。多重轉移語句不易維護,它把採取哪一種算法或採取哪一種行爲的邏輯與算法或行爲的邏輯混合在一起,統統列在一個多重轉移語句裏面,比使用繼承的辦法還要原始和落後。
缺點
- 客戶端必須知道所有的策略類,並自行決定使用哪一個策略類。這就意味着客戶端必須理解這些算法的區別,以便適時選擇恰當的算法類。換言之,策略模式只適用於客戶端知道所有的算法或行爲的情況。
6.在Android中的使用示例
在Android中,插值器的實現是通過策略設計模式實現
TimeInterpolator爲策略接口,LinearInterpolator、AccelerateInterpolator爲具體的實現類。
public interface TimeInterpolator {
/**
*
* @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);
}
- LinearInterpolator
public class LinearInterpolator extends TimeInterpolator {
public LinearInterpolator() {
}
//...
public float getInterpolation(float input) {
return input;
}
//...
}
- AccelerateInterpolator
@HasNativeInterpolator
public class AccelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
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) {
this(context.getResources(), context.getTheme(), attrs);
}
/** @hide */
public AccelerateInterpolator(Resources res, Theme theme, AttributeSet attrs) {
TypedArray a;
if (theme != null) {
a = theme.obtainStyledAttributes(attrs, R.styleable.AccelerateInterpolator, 0, 0);
} else {
a = res.obtainAttributes(attrs, R.styleable.AccelerateInterpolator);
}
mFactor = a.getFloat(R.styleable.AccelerateInterpolator_factor, 1.0f);
mDoubleFactor = 2 * mFactor;
setChangingConfiguration(a.getChangingConfigurations());
a.recycle();
}
public float getInterpolation(float input) {
if (mFactor == 1.0f) {
return input * input;
} else {
return (float)Math.pow(input, mDoubleFactor);
}
}
}