策略模式的定义
定义一系列的算法,把每一个算法封装起来,并且使它们可相互替换。策略模式模式使得算法可独立于使用它的客户而变化。
- 策略模式属于行为型模式。
- 策略模式提供了一组算法给客户端调用,使得客户端能够根据不同的条件来选择不同的策略来解决不同的问题。
- 如排序算法,可以使用冒泡排序、快速排序等等。
UML类图
Stragety(抽象策略类):抽象类或接口,提供具体策略类需要实现的接口。
ConcreteStragetyA、ConcreteStragetyB(具体策略类):具体的策略实现,封装了相关的算法实现。
Context(环境类):用来操作策略的上下文环境。
策略模式应用
我以游客出行方式的例子讲解应用策略模式前后的区别,出行方式有自驾、火车、飞机等等。
/**
* 游客类
*/
public class Tourist {
/**
* 根据旅游方式选择出行
*
* @param way 旅游方式的英文拼写
*/
public void travel(String way) {
switch (way) {
case "car":
System.out.println("自驾去旅游~");
break;
case "train":
System.out.println("坐火车去旅游~");
break;
case "airplane":
System.out.println("坐飞机去旅游~");
break;
}
}
}
不使用策略模式时,针对游客的多种出行方式选择,我们可以使用switch语句或if-else语句满足,但是这种方式违反了开闭原则,不利于扩展,当我们增加新的出行方式时,还要修改源码。
那么用策略模式会是怎样呢?对应上面的UML类图修改后代码如下。
/**
* 出行策略接口
*/
public interface ITravel {
void travel();
}
/**
* 具体的出行策略类(自驾)
*/
public class CarTravel implements ITravel {
@Override
public void travel() {
System.out.println("自驾去旅游~");
}
}
/**
* 具体的出行策略类(火车)
*/
public class TrainTravel implements ITravel {
@Override
public void travel() {
System.out.println("坐火车去旅游~");
}
}
/**
* 具体的出行策略类(飞机)
*/
public class AirplaneTravel implements ITravel {
@Override
public void travel() {
System.out.println("坐飞机去旅行~");
}
}
/**
* 游客类
*/
public class Tourist {
/**
* 根据不同的策略选择出行方式
*
* @param travel 实现了抽象策略的策略类
*/
public void travel(ITravel travel) {
travel.travel();
}
}
public class Demo {
public static void main(String args[]) {
Tourist tourist = new Tourist();
//汽车出行
tourist.travel(new CarTravel());
//火车出行
tourist.travel(new TrainTravel());
//飞机出行
tourist.travel(new AirplaneTravel());
}
}
自驾去旅游~
坐火车去旅游~
坐飞机去旅行~
使用策略模式后不同的出行方式被单独封装了起来,省去了if-else和switch语句复杂的判断。当添加新的出行方式时,也无需修改源码,比如添加一个坐火箭的出行方式,只需新建一个类实现抽象接口的方法即可。
/**
* 新增的具体出行策略类(火箭)
*/
public class RocketTravel implements ITravel{
@Override
public void travel() {
System.out.println("坐火箭去旅行~");
}
}
//火箭出行
tourist.travel(new RocketTravel());
坐火箭去旅行~
策略模式的优缺点
优点:
- 策略类可以互相替换
- 耦合度低,方便扩展,符合开闭原则
- 避免使用多重条件选择语句(if-else或者switch)
缺点:
- 策略的增多会导致子类的也会变多
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
策略模式在Android源码中的应用
策略模式在Android源码中有着大量的应用,例如
- ListView设置的Adapter适配器
- ValueAnimator设置的Interpolator插值器
- ViewPager设置的PagerTransformer切换效果
拿ViewPager设置PagerTransformer来说
pager.setPageTransformer(boolean reverseDrawingOrder,
@Nullable PageTransformer transformer);
PagerTransformer就是一个切换效果的抽象接口
public interface PageTransformer {
void transformPage(@NonNull View page, float position);
}
且看官方的两个具体切换效果类就是实现了这个抽象接口
//缩小页面转换器
public class ZoomOutPageTransformer implements ViewPager.PageTransformer{}
//深度页面转换器
public class DepthPageTransformer implements ViewPager.PageTransformer{}
ListView和ValueAnimator也是如此,由此可见,策略模式根据不同的方案,可实现抽象接口定制具体实现,极大的提升了程序的可扩展性,同时又遵守了开闭原则。