策略模式
# 一、概述
策略(Strategy)模式定义一系列算法,并将每种算法分别放入独立的类中,以使算法对象可以互相替换。每一种算法代表一种策略。
当可以使用不同的算法(策略)处理同一个问题的时候,就可以考虑使用策略模式。
# 1.1 解决了什么问题
策略模式很经典的一个案例是解决路线规划问题。
据北京警方通告,著名男明星李某某经常会在晚上空虚的时候邀请漂亮异性到家里打发无聊时间,Happy 结束之后该异性要回家了,要根据回家时间以及回家距离为其推荐回家的交通方式,那么代码可能是这样的:
public static void backHome(String way, float distance) {
float fee;
switch (way) {
case "taxi":
// 出租车的起步价为15,超过2公里每公里5块
if (distance <= 2) {
fee = 15;
} else {
fee = (distance - 2) * 5 + 15;
}
System.out.println("出租车需要 " + fee + " 元");
break;
case "didi":
// didi的计费方式和出租车一样,但是最近统一优惠10块
if (distance <= 2) {
fee = 15;
} else {
fee = (distance - 2) * 5 + 15 - 10;
}
System.out.println("滴滴需要 " + fee + " 元");
break;
case "subway":
fee = (int) (distance / 5) * 2;
System.out.println("地铁需要 " + fee + " 元");
break;
default:
break;
}
}
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
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
这样实现起来是没问题的,但是李某某怕打车或坐地铁留下证据,毕竟自己是公众人物,万一后来被警察叔叔抓住把柄可就不好了。于是乎要求该女子步行回家,这时候程序员就得在上面的方法中加一个case
分支,万一李某某下次要求人家先走一半然后再打车,那岂不是得再加一个case
分支,那代码可就不好维护了。
# 1.2 解决方案
抽取一个公用接口,其中定义一个计算交通费用的方法。然后将不同的交通方式都定义为一个类,每个类都实现了前面那个接口。定义一个上下文类,该类中定义一个backHome
方法,将不同的交通方式类作为参数传递到方法内部。
# 二、实现方式
# 2.1 角色
- Strategy:是所有具体策略的通用接口,它声明了一个上下文用于执行策略的方法。
- ConcreteStrategies:实现了上下文所用算法的各种不同变体。
- Context:维护指向具体策略的引用,且仅通过策略接口与该对象进行交流。
# 2.2 代码
定义 Strategy 接口:
public interface Strategy {
void caculateFee(float distance);
}
1
2
3
2
3
定义具体的策略:
public class TaxiStrategy implements Strategy {
@Override
public void caculateFee(float distance) {
float fee;
if (distance <= 2) {
fee = 15;
} else {
fee = (distance - 2) * 5 + 15;
}
System.out.println("出租车需要 " + fee + " 元");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
public class DidiStrategy implements Strategy {
@Override
public void caculateFee(float distance) {
float fee;
if (distance <= 2) {
fee = 15;
} else {
fee = (distance - 2) * 5 + 15 - 10;
}
System.out.println("滴滴需要 " + fee + " 元");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
public class SubwayStrategy implements Strategy {
@Override
public void caculateFee(float distance) {
float fee = (int) (distance / 5) * 2;
System.out.println("地铁需要 " + fee + " 元");
}
}
1
2
3
4
5
6
7
2
3
4
5
6
7
public class WalkStrategy implements Strategy {
@Override
public void caculateFee(float distance) {
System.out.println("步行回家不花钱,但是容易被警察叔叔拦下来盘问");
}
}
1
2
3
4
5
6
2
3
4
5
6
定义策略 Context,负责通过策略接口和具体策略对象交互:
public class StrategyContext {
public void backHome(Strategy strategy, float distance) {
strategy.caculateFee(distance);
}
}
1
2
3
4
5
2
3
4
5
客户端:
public class StrategyTest {
public static void main(String[] args) {
StrategyContext strategy = new StrategyContext();
strategy.backHome(new TaxiStrategy(), 10);
strategy.backHome(new DidiStrategy(), 10);
strategy.backHome(new SubwayStrategy(), 10);
strategy.backHome(new WalkStrategy(), 10);
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
出租车需要 55.0 元
滴滴需要 45.0 元
地铁需要 4.0 元
步行回家不花钱,但是容易被警察叔叔拦下来盘问
1
2
3
4
2
3
4
# 三、源码中的应用
java.util.Comparator#compare()
上次更新: 2023/11/01, 03:11:44