看下策略模式的定义
策略模式定义了一些列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变换。
乍一看,也没看出个所以然来。还是举栗说明简单明了。
假设我们要出去旅游,而去旅游出行的方式有很多,有开车自驾,有坐高铁,有坐飞机等等。而如果不使用任何模式,我们的代码可能就是这样子的。
public class TravelStrategy {
enum Strategy{
WALK,PLANE,HIGHSPEED
}
private Strategy strategy;
public TravelStrategy(Strategy strategy){
this.strategy=strategy;
}
public void travel(){
if(strategy==Strategy.WALK){
print("walk");
}else if(strategy==Strategy.PLANE){
print("plane");
}else if(strategy==Strategy.HIGHSPEED){
print("highspeed");
}
}
public void print(String str){
System.out.println("出行旅游的方式为:"+str);
}
public static void main(String[] args) {
TravelStrategy walk=new TravelStrategy(Strategy.WALK);
walk.travel();
TravelStrategy plane=new TravelStrategy(Strategy.PLANE);
plane.travel();
TravelStrategy highspeed=new TravelStrategy(Strategy.HIGHSPEED);
highspeed.travel();
}
}
这样做有一个致命的缺点,一旦出行的方式要增加,我们就不得不增加新的else if语句,而这违反了设计的原则之一,对修改封闭。而这时候,策略模式则可以完美的解决这一切。
首先,需要定义一个策略接口。
public interface Strategy {
void travel();
}
然后根据不同的出行方式实行对应的接口
public class PlaneStrategy implements Strategy{
@Override
public void travel() {
System.out.println("plane travel");
}
}
public class WalkStrategy implements Strategy{
@Override
public void travel() {
System.out.println("walk travel");
}
}
public class HighSpeedStrategy implements Strategy{
@Override
public void travel() {
System.out.println("highSpeed travel");
}
}
此外还需要一个包装策略的类,并调用策略接口中的方法
public class TravelPack {
Strategy strategy;
public Strategy getStrategy() {
return strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void travel() {
if (strategy != null) {
strategy.travel();
}
}
}
测试一下代码(此处是kotlin)
val travelPack = TravelPack()
travelPack.strategy = PlaneStrategy()
travelPack.travel()
travelPack.strategy = WalkStrategy()
travelPack.travel()
travelPack.strategy = HighSpeedStrategy()
travelPack.travel()
输出结果:
plane travel
walk travel
highspeed travel
可以看到,应用了策略模式后,如果我们想增加新的出行方式,完全不必要修改现有的类,我们只需要实现策略接口即可,这就是设计原则中的对扩展开放准则。假设现在我们增加了一种开车出行的方式。只需新增一个类即可。
public class CarStrategy implements Strategy{
@Override
public void travel() {
System.out.println("car travel");
}
}
之后设置策略即可
travelPack.strategy = CarStrategy()
travelPack.travel()
而在Android的系统源码中,策略模式也是应用的相当广泛的,比较典型的就是属性动画中的应用。
在属性动画中,有一个东西叫做插值器,它的作用就是根据时间流逝的百分比来来计算出当前属性值改变的百分比。
我们使用属性动画的时候,可以通过set方法对插值器进行设置。可以看到内部维持了一个时间插值器的引用,并设置了getter和setter方法,默认情况下是先加速后减速的插值器,set方法如果传入的是null,则是线性插值器。而时间插值器TimeInterpolator是个接口,有一个接口继承了该接口,就是Interpolator这个接口,其作用是为了保持兼容。
private static final TimeInterpolator sDefaultInterpolator =
new AccelerateDecelerateInterpolator();
private TimeInterpolator mInterpolator = sDefaultInterpolator;
@Override
public void setInterpolator(TimeInterpolator value) {
if (value != null) {
mInterpolator = value;
} else {
mInterpolator = new LinearInterpolator();
}
}
@Override
public TimeInterpolator getInterpolator() {
return mInterpolator;
}
public interface Interpolator extends TimeInterpolator {
// A new interface, TimeInterpolator, was introduced for the new android.animation
// package. This older Interpolator interface extends TimeInterpolator so that users of
// the new Animator-based animations can use either the old Interpolator implementations or
// new classes that implement TimeInterpolator directly.
}
此外还有一个BaseInterpolator插值器实现了Interpolator接口,并且是一个抽象类
abstract public class BaseInterpolator implements Interpolator {
private int mChangingConfiguration;
/**
* @hide
*/
public int getChangingConfiguration() {
return mChangingConfiguration;
}
/**
* @hide
*/
void setChangingConfiguration(int changingConfiguration) {
mChangingConfiguration = changingConfiguration;
}
}
平时我们使用的时候,通过设置不同的插值器,实现不同的动画速率变换效果,比如线性变换,回弹,自由落体等等。这些都是插值器接口的具体实现,也就是具体的插值器策略。我们略微来看几个策略。
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
public LinearInterpolator() {
}
public LinearInterpolator(Context context, AttributeSet attrs) {
}
public float getInterpolation(float input) {
return input;
}
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createLinearInterpolator();
}
}
public class AccelerateDecelerateInterpolator extends BaseInterpolator
implements NativeInterpolatorFactory {
public AccelerateDecelerateInterpolator() {
}
@SuppressWarnings({"UnusedDeclaration"})
public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
}
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator();
}
}
内部使用的时候直接调用getInterpolation方法就可以返回对应的值了,也就是属性值改变的百分比。
Android系统中还有几个常见的,比如属性动画中另外一个应用策略模式的地方就是估值器,它的作用是根据当前属性改变的百分比来计算改变后的属性值。该属性和插值器是类似的,有几个默认的实现;还有之前很早用的Listview,其中设置adapter的时候,可以发现 ListAdapter 就是 strategy 接口,,ArrayAdpater 等就是具体的实现类。