策略模式
在策略模式中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的context对象。策略对象改变 context 对象的执行算法。
策略模式是一种行为型模式,它将对象和行为分开,将行为定义为 一个行为接口 和 具体行为的实现。策略模式最大的特点是行为的变化,行为之间可以相互替换。每个if判断都可以理解为就是一个策略。本模式使得算法可独立于使用它的用户而变化。
1. 介绍
意图:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。
主要解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
何时使用:一个系统有许多许多类,而区分它们的知识他们直接的行为。
如何解决:将这些算法封装成一个一个的类,任意地替换。
关键代码:实现同一个接口。
应用实例:
- 诸葛亮的锦囊妙计,每一个锦囊就是一个策略。
- 旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略
- Java AWT中的 LayoutManager
优点:
- 算法可以自由切换。
- 避免使用多重条件判断。
- 扩展性良好。
- 策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
缺点:
- 策略类会增多,可以通过使用享元模式在一定程度上减少对象的数量。
- 所有策略类都需要对外暴露。即客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
使用场景:
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
- 一个系统需要动态地在几种算法中选择一种。
- 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
注意事项:如果一个系统的策略多于四个,就需要考虑混合模式,解决策略类膨胀的问题。
2. 模式结构
策略模式包含如下角色:
- Strategy:抽象策略类。策略是一个接口,该接口定义若干个算法标识,即定义了若干个抽象方法。
- Context:环境类/上下文类
- 上下文是依赖于接口的类(是面向策略设计的类),即上下文包含用策略(接口)声明的变量。
- 上下文提供一个方法,该方法委托策略变量调用具体策略所实现的策略接口中的方法(实现接口的类重写策略(接口)中的方法,来完成具体功能)
- 具体策略类:策略实现类,具体策略是实现策略接口的类。具体策略实现策略接口所定义的抽象方法,即给出算法标识的具体方法。(说白了就是重写策略类的方法!)
3. 示例
示例1
现在将创建一个将定义加、减、乘计算的策略接口(Strategy接口)和实现了Strategy接口的实体策略类。Context 是一个使用了某种策略的类。
StrategyPatternDemo是测试类,使用 Context 和策略对象来掩饰 Context 在它所配置或使用的策略 改变时的行为变化。
步骤一:创建一个策略接口
public interface Strategy {
public int doOperation(int num1, int num2);
}
步骤二:创建接口的实现类
OperationAdd类:
public class OperationAdd implements Strategy {
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
OperationSubtract类:
public class OperationSubtract implements Strategy {
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
OperationMultiply类:
public class OperationMultiply implements Strategy {
@Override
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
步骤三:创建 Context 类
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2) {
return strategy.doOperation(num1,num2);
}
}
步骤四:使用 Context 来查看当它改变策略 Strategy 时的行为变化。
public class StrategyPatternDemo {
public static void main(String[] args) {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10,5));
context = new Context(new OperationSubtract());
System.out.println("10 - 5 = " + context.executeStrategy(10,5));
context = new Context(new OperationMultiply());
System.out.println("10 * 5 = " + context.executeStrategy(10,5));
}
}
步骤五:执行程序,输出结果:
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50
示例2
现在有一个商店售卖货物,但是针对不同的人会有折扣,目前的折扣是普通人不打折,中级人士是打折10%,高级人士是20%,传统实现如下:
public Double computeMoney(String type, Double primitivemoney, int n) {
// 中级计费
if (type.equals("middle")) {
return primitivemoney * n - primitivemoney * n * 0.1;
}
// 高级计费
if (type.equals("high")) {
return primitivemoney * n - primitivemoney * n * 0.2;
}
// 初级 计费
return primitivemo\ney;
}
现在用策略模式实现:
步骤一:创建策略接口
public interface ComputeStrategy {
/**
* 计算money的抽象方法
* @param money 单价
* @param n 数量
* @return
*/
public double compute(double money, int n);
}
步骤二:创建接口的实现类
普通人士:
public class PrimaryMember implements ComputeStrategy {
// 初级不打折
@Override
public double compute(double money, int n) {
return money * n;
}
}
中级人士:
public class MiddleMember implements ComputeStrategy {
// 中级 10%
@Override
public double compute(double money, int n) {
return money * n - money * n * 0.1;
}
}
高级人士:
public class HighMember implements ComputeStrategy {
// 高级 20%
@Override
public double compute(double money, int n) {
return money * n - money * n * 0.2;
}
}
步骤三:创建Context类
public class MemberContext {
private ComputeStrategy computeStrategy;
public MemberContext(ComputeStrategy computeStrategy) {
this.computeStrategy = computeStrategy;
}
public double computeMoney(double money, int n) {
return computeStrategy.compute(money, n);
}
}
步骤四:测试
public static void main(String[] args) {
//具体的行为策略
ComputeStrategy primary = new PrimaryMember();
ComputeStrategy middle = new MiddleMember();
ComputeStrategy high = new HighMember();
// 用户选择不同的策略
MemberContext primaryContext = new MemberContext(primary);
MemberContext middleContext = new MemberContext(middle);
MemberContext highContext = new MemberContext(high);
// 计算 单价300 数量1
System.out.println("普通价: "+ primaryContext.computeMoney(300,1));
System.out.println("中级价: "+ middleContext.computeMoney(300,1));
System.out.println("高级价: "+ highContext.computeMoney(300,1));
}
步骤五:运行程序,输出结果:
普通价: 300.0
中级价: 270.0
高级价: 240.0
4. 策略模式适用场景
在如下情况可以使用策略模式:
- 一个系统需要动态地在几种算法中选择一种。
- 如果一个对象有很多行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
- 如果在一个系统里面有许多类,它们之间的区别仅在于他们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
- 不希望客户端知道复杂的、与算法相关的数据结构,在具体策略类中封装算法和相关的数据结构,提高算法的保密性与安全性。
在生活中比较常见的应用模式有:
1、电商网站支付方式,一般分为银联、微信、支付宝,可以采用策略模式
2、电商网站活动方式,一般分为满减送、限时折扣、包邮活动,拼团等可以采用策略模式