设计模式专栏
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);
}
public class LinearInterpolator extends TimeInterpolator {
public LinearInterpolator() {
}
//...
public float getInterpolation(float input) {
return input;
}
//...
}
@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);
}
}
}