设计模式之策略模式

策略模式属于对象的行为模式,其用意是针对一组算法,将每一个算法封装到具有公共接口独立的类中,从而在不影响客户端的情况下可以切换相应的算法。

未使用策略模式案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class TravelStrategy {
enum Strategy{
WALK,PLANE,SUBWAY
}
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.SUBWAY){
print("subway");
}
}

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 subway=new TravelStrategy(Strategy.SUBWAY);
subway.travel();
}
}

通过switch或者if语句,来判断选择哪一种策略算法,一旦策略增加或者减少修改,就不得不增加新的语句,这就违背了面向对象的原则之一,对修改封闭。

使用策略模式案例

定义策略接口(抽象策略)

1
2
3
public interface Strategy {
void travel();
}

将不同的算法封装到实现该策略接口的具体的类中(具体策略)

1
2
3
4
5
6
7
8
public class WalkStrategy implements Strategy{

@Override
public void travel() {
System.out.println("walk");
}

}
1
2
3
4
5
6
7
8
public class PlaneStrategy implements Strategy{

@Override
public void travel() {
System.out.println("plane");
}

}
1
2
3
4
5
6
7
8
public class SubwayStrategy implements Strategy{

@Override
public void travel() {
System.out.println("subway");
}

}

策略环境(持有抽象策略引用的环境类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class TravelContext {
Strategy strategy;

public Strategy getStrategy() {
return strategy;
}

public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}

public void travel() {
if (strategy != null) {
strategy.travel();
}
}
}

具体使用

1
2
3
4
5
6
7
8
9
10
11
public class Main {
public static void main(String[] args) {
TravelContext travelContext=new TravelContext();
travelContext.setStrategy(new PlaneStrategy());
travelContext.travel();
travelContext.setStrategy(new WalkStrategy());
travelContext.travel();
travelContext.setStrategy(new SubwayStrategy());
travelContext.travel();
}
}

若想增加新的策略(添加新的策略实现类即可)

1
2
3
4
5
6
7
8
public class BikeStrategy implements Strategy{

@Override
public void travel() {
System.out.println("bike");
}

}
1
2
3
TravelContext travelContext=new TravelContext();
travelContext.setStrategy(new BikeStrategy());
travelContext.travel();

总结

面向对象的对修改封闭对扩展开放

Android源码中的使用

  • 属性动画的插值器

策略接口

1
2
3
4
5
public interface TypeEvaluator<T> {

public T evaluate(float fraction, T startValue, T endValue);

}

多个策略实现例如

1
2
3
4
5
6
7
public class IntEvaluator implements TypeEvaluator<Integer> {

public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
}
1
2
3
4
5
6
7
public class FloatEvaluator implements TypeEvaluator<Number> {

public Float evaluate(float fraction, Number startValue, Number endValue) {
float startFloat = startValue.floatValue();
return startFloat + fraction * (endValue.floatValue() - startFloat);
}
}

其他略…

其他使用场景举例

例如:一个电商类平台等购物车系统,除了把货品的单价乘以数量之外,可能会有一些优惠活动。比如说,对高级会员提供5折优惠,对中级会员提供7折优惠,对初级会员提供9折优惠

那么这就涉及到了三种算法

首先定义折扣抽样策略接口

1
2
3
4
5
6
7
8
public interface MemberStrategy {
/**
* 计算图书的价格
* @param booksPrice 图书的原价
* @return 计算出打折后的价格
*/
public double calcPrice(double booksPrice);
}

初级会员折扣策略

1
2
3
4
5
6
7
8
9
10
public class PrimaryMemberStrategy implements MemberStrategy {

@Override
public double calcPrice(double booksPrice) {

System.out.println("对于初级会员的9折折扣");
return booksPrice*0.9;
}

}
1
2
3
4
5
6
7
8
9
public class AdvancedMemberStrategy implements MemberStrategy {

@Override
public double calcPrice(double booksPrice) {

System.out.println("对于高级会员的折扣为5折");
return booksPrice * 0.5;
}
}
1
2
3
4
5
6
7
8
9
10
public class IntermediateMemberStrategy implements MemberStrategy {

@Override
public double calcPrice(double booksPrice) {

System.out.println("对于中级会员的折扣为7折");
return booksPrice * 0.7;
}

}

策略环境类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Price {
//持有一个具体的策略对象
private MemberStrategy strategy;
/**
* 构造函数,传入一个具体的策略对象
* @param strategy 具体的策略对象
*/
public Price(MemberStrategy strategy){
this.strategy = strategy;
}

/**
* 计算图书的价格
* @param booksPrice 图书的原价
* @return 计算出打折后的价格
*/
public double quote(double booksPrice){
return this.strategy.calcPrice(booksPrice);
}
}

客户端的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Client {

public static void main(String[] args) {
//选择并创建需要使用的策略对象
MemberStrategy strategy = new AdvancedMemberStrategy();
//创建环境
Price price = new Price(strategy);
//计算价格
double quote = price.quote(300);
System.out.println("图书的最终价格为:" + quote);
}

}

可以看出

  1. 策略模式的重心不是提供算法,而是对多种算法的封装
  2. 各个算法相对独立平等
  3. 算法可以相互切换,但在同一时刻只能使用一种策略
  4. 面向对象的:对修改封闭,对拓展开放
  5. 避免使用switch和if多重条件语句,方便维护
  6. 缺点:客户端事先知道有多少种策略,并且每个策略的区别
文章目录
  1. 1. 未使用策略模式案例
  2. 2. 使用策略模式案例
  3. 3. Android源码中的使用
  4. 4. 其他使用场景举例