当我们写代码时总会遇到一种情况,就是我们会有很多的选择,由此衍生出很多的if…else,或者case。如果每个条件语句中包含了一个简单的逻辑,那还比较容易处理;但如果在一个条件语句中又包含了多个条件语句,就会使得代码变得臃肿,维护的成本也会加大,这显然违背了开放封闭原则。
策略模式定义:- 策略是对算法的封装,是一种形为模式,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换
- 是一种行为模式,对算法封装,使得客户端独立于各个策略
- 扩展性强,添加策略无非就是添加一个具体的实现类而已,代价非常低
- 某些业务中,某一个行为,会有多个实现类,并且在一次运行中,当前业务只会选择一种实现类
- 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。
- 使用策略模式可以避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重条件语句里面,比使用继承的办法还要原始和落后。
- 使用策略模式可以避免使用多重条件语句。多重条件语句不易维护,而且易出错。
- 易于拓展。当需要添加一个策略时,只需要实现接口就可以了。
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。
- 由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。
下面的例子来源:https://blog.csdn.net/dfskhgalshgkajghljgh/article/details/102766832
针对同一个行为,可以选择不同的策略方式去实现,例如我们在选择支付方式时,可以有微信、支付宝、各类银行卡支付等方式,如果不使用策略模式,很容易写出下面的代码:
public void pay(String payType) {
if ("weixin".equals(payType)) {
//调用微信支付SDK
System.out.println("您选择的微信支付");
} else if ("aili".equals(payType)) {
//调用支付宝支付SDK
System.out.println("您选择的支付宝支付");
} else if ("yinhangcard".equals(payType)) {
//调用银行卡支付SDK
System.out.println("您选择的银行卡支付");
} else {
System.out.println("您选择的支付方式暂未开通");
}
}
若是逻辑简单的话还好,逻辑复杂的话会有较为明显的问题:
- if...else...多层嵌套,如果内部有更多的逻辑,嵌套会非常复杂;
- 如果又添加了更多的支付方式的话,pay的代码还要修改,无法对程序进行很好的扩展。
因此为了较好的扩展程序,我们应该针对接口编程,而不是针对实现编程。那么我们使用策略模式来解决上述写法所面临的问题:
行为接口:
public interface Payment {
void pay(String price);
}
具体的支付方式:
public class WeixinPay implements Payment{
@Override
public void pay(String price) {
System.out.println("微信支付" + price);
}
}
public class AliPay implements Payment {
@Override
public void pay(String price) {
System.out.println("阿里支付" + price);
}
}
外界和具体策略进行连接的设置类(参数是具体的实现):
public class ShopCart {
private Payment payment;
public ShopCart(Payment pay) {
this.payment = pay;
}
public void pay(String price) {
payment.pay(price);
}
}
用来操作策略的上下文环境,起到承上启下的作用,屏蔽高层模块对策略、算法的直接访问,在这里我们需要知道针对不同的情况使用哪种策略行为,这里就是原来的嵌套的多层if...else...的地方,现在我们只需要在不同的情况下使用不同的策略即可:
ShopCart shopCartWeinxin = new ShopCart(new WeixinPay());
shopCartWeinxin.pay("22");
ShopCart shopCartAli = new ShopCart(new AliPay());
shopCartAli.pay("33");
采用策略模式后,当新增支付方式时,只需要实现一个继承Payment接口的类即可,Shopcart类不需要做任何改动,做到了对修改关闭,对扩展开放的原则,同时也做到针对接口编程,而不是针对实现编程的设计原则。其实真正的项目中,Shopcart是个很复杂的类,里面会有很多业务逻辑,在新增业务不改动旧逻辑,会增加项目的稳定性,也减少测试的工作投入。
源码中所使用策略模式:
- 动画插值器TimeInterpolator设置不同的插值器,动画可以以不同的速度模型来执行
- listview的adapter
- RecyclerView.LayoutManager
一个整体的简单示例:
interface MathAlgorithm {
public int calculate(int num1, int num2);
}
class MathAdd implements MathAlgorithm{
@Override
public int calculate(int num1, int num2) {
return num1 + num2;
}
}
class MathSubstract implements MathAlgorithm{
@Override
public int calculate(int num1, int num2) {
return num1 - num2;
}
}
class MathMultiply implements MathAlgorithm{
@Override
public int calculate(int num1, int num2) {
return num1 * num2;
}
}
class MathContext {
private MathAlgorithm algorithm;
public MathContext(MathAlgorithm strategy){
this.algorithm = strategy;
}
public int execute(int num1, int num2){
return algorithm.calculate(num1, num2);
}
}
public class Main {
public static void main(String[] args) {
MathContext context = new MathContext(new MathAdd());
System.out.println("10 + 5 = " + context.execute(10, 5));
context = new MathContext(new MathSubstract());
System.out.println("10 - 5 = " + context.execute(10, 5));
context = new MathContext(new MathMultiply());
System.out.println("10 * 5 = " + context.execute(10, 5));
}
}
参考文章链接:
https://blog.csdn.net/dfskhgalshgkajghljgh/article/details/102766832
https://www.jianshu.com/p/135532803cdb