定义
策略模式定义了一组算法,将它们逐个封装起来,并使它们可以相互替换。策略可以让算法独立于使用它们的客户而变化。
往往官方给的定义就是很难理解,其实就是定义一个接口,分别让具有相同行为的类去实现它,成为一种策略,然后根据不同需求调用不同类中的方法。通过不同的方式(算法)达到相同的目的(功能)。
说明
举个例子吧,我们在购物时,普通用户打9折,会员打8折,超级会员打6折。
此时我们就可以定义一个花费的接口 double cost(Double oldCost);
作用就是计算出打折后应付的钱数。
然后我们设计不同的用户类来实现这个接口,比如普通用户类,如下代码:
@Override
public double cost(Double oldCost) {
return oldCost * 0.9;
}
然后会员和超级会员类似。这样就算配置了不同的策略
现在你一定会问:那怎么来区分当前用户属于哪一个用户呢?if-else吗?
当然不是,用策略模式的目的就是消除if-else带来的耦合,提高代码的扩展和维护性,所以此时我们就需要一个Context即上下文对象,说白了就是负责调用对应的算法,策略的类。有了这个类,它就可以自动的调用对应的策略从而完成费用的。
使用场景
什么时候使用:当你的if-else多余四个的时候就可以考虑使用策略设计模式了。
下面就将购物计算费用这个例子完整写出来。在写出来之前先来确定一下需要哪些类
- Customer 消费的公共接口,计算打折后费用
- Cashier 收银员,负责分级用户类型调用对应策略。
- CommonCustomer 普通用户,即打0.9折,其他两个类似
例子
消费的公共接口 Customer.java
public interface Customer {
/**
* 计算折扣后的花费
*
* @param oldCost 原花费
* @return 折扣后的花费
*/
double cost(Double oldCost);
}
收银员类 Cashier .java
public class Cashier {
private Customer customer;
private double cost(Double oldCost) {
return customer.cost(oldCost);
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
普通用户 CommonCustomer.java
public class CommonCustomer implements Customer {
@Override
public double cost(Double oldCost) {
return oldCost * 0.95;
}
}
会员 SuperCustomer.java
public class SuperCustomer implements Customer {
@Override
public double cost(Double oldCost) {
return oldCost * 0.8;
}
}
超级会员 VIPCustomer.java
public class VIPCustomer implements Customer {
@Override
public double cost(Double oldCost) {
return oldCost * 0.6;
}
}
测试类
/**
* 举一个收银的例子,普通用户打95折,会员打8折,超级会员打6折。
*/
public class Test {
public static void main(String[] args) {
Cashier cashier = new Cashier();
// 普通会员
CommonCustomer commonCustomer = new CommonCustomer();
cashier.setCustomer(commonCustomer);
System.out.println("普通会员:" + commonCustomer.cost(100.0));
// 一般会员
SuperCustomer superCustomer = new SuperCustomer();
cashier.setCustomer(superCustomer);
System.out.println("普通会员:" + commonCustomer.cost(100.0));
// 超级会员
VIPCustomer vipCustomer = new VIPCustomer();
cashier.setCustomer(vipCustomer);
System.out.println("超级会员:" + commonCustomer.cost(100.0));
}
}
优点
- 算法可以自由切换
- 改一下策略很方便
- 扩展性良好
- 增加一个策略,就多增加一个类就好了。
缺点
- 策略类的数量增多
- 每一个策略都是一个类,复用的可能性很小、类数量增多
- 所有的策略类都需要对外暴露
- 上层模块必须知道有哪些策略,然后才能决定使用哪一个策略