引言
前一篇文章[设计模式——行为型模式之通过中介者模式实现各模块之间的解耦 [(http://blog.csdn.net/crazymo_/article/details/73527482)总结行为型模式中的中介者模式,通过中介者模式我们可以让各模块专注于自己的核心工作,二把交互等次要问题交给中介者,实现一定程度的解耦,今天就接着总结另一种简单而又有效的行为型模式,相信大家对于if-else if-else 应该再也熟悉不过,也肯定曾经想过如何去减少使用不必要的if-else if-else 和switch这样的条件语句,学习了策略模式之后,你会发现原来代码还可以更简洁。附行为型设计模式系列文章列表:
- 设计模式——行为型之使用模板方法(Template Method Pattern)模式尽量减少重复相似的代码段(一)
- 设计模式——行为型模式之通过中介者模式(Mediator Pattern)实现各模块之间的解耦(二)
- 设计模式——行为型模式之借助策略模式(Strategy Pattern)减少使用不必要的if-else if -else和switch-case(三)
- 设计模式——行为型设计模之借助观察者模式(Observer Pattern)实现模块之间的解耦(四)
- 设计模式——行为型模式之借助责任链模式(Chain of Responsibility)灵活完成链式处理(五)
- 设计模式——行为型之命令模式(Command Pattern)让你的命令发起者和命令执行者的逻辑解耦(六)
- 设计模式——行为型之使用备忘录模式(Memento Pattern)随时回滚状态(七)
- 设计模式——行为型模式之借助策略模式(Strategy Pattern)减少使用不必要的if-else if -else和switch-case(八)
一、策略模式概述
策略模式(Strategy Pattern)也有叫做政策模式(Policy Pattern)的 是一种比较简单的行为型模式——定义一组算法,将每个算法都封装起来,并且使它们之间可以互换(Define a family of algorithms,encapsulate each one,and make them interchangeable)。简而言之,首先定义一组算法继承同一接口或者抽象类,然后将算法封装到一个上下文类中,最后通过上下文类去调用算法而非算法自身的实现类。所以通常策略模式的主要参与角色:Conext上下文封装策略类、Strategy抽像策略类、ConreteStrateg具体抽象类。
二、策略模式的优点和缺点及可用场景
1、策略模式的优点
结构清晰,使用简单,代码简捷易读易扩展
高内聚低耦合
封装可以更为彻底,数据分离
策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。
- 使用策略模式可以避免使用if-else if-else、switch-case等多重条件语句。大量多重条件语句不易维护,而且代码也不够简洁,它把采取哪一种算法的逻辑与行为的逻辑实现在一起,统统列在一个多重条件语句里面,比使用继承的办法还要原始和落后。
2、策略模式的缺点
由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。
所有的策略类都必须对客户端完全可见,这意味着客户端得对这些策略思想完全理解,并由客户自行决定使用哪一个策略类,从一定程度上说增加了客户端的成本。
3、策略模式的可用场景及注意事项
当一组算法对应一个任务,并且程序可以在运行时灵活的选择其中一个算法,策略模式是很好的选择。
需要安全的封装平等的多种不同类型操作
当同一抽象类拥有很多具体子类时且程序运行的时候需要动态决定使用哪一具体类时
策略模式的重心不是如何实现算法,而是关注如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。
策略模式中各个策略算法的平等性。对于一系列具体的策略算法,大家的地位是完全一样的,正因为这个平等性,才能实现算法之间可以相互替换。所有的策略算法在实现上也是相互独立的,相互之间是没有依赖的。
- 运行时策略的互斥性,策略模式在运行的每一个时刻只能使用这组被封装算法中的某一个,虽然可以动态地在不同的策略实现中切换,但是同时只能使用一个。
- 策略的抽象实现,当所有的具体策略类都有一些公有的行为。此时根据设计原则应把这些公有的行为放到共同的抽象策略角色Strategy类里面。
三、策略模式的实现
策略模式本质就是对已知的实现同一任务的一组算法进行统一封装,从而把使用算法的调用和算法实现本身分割开来,再把算法的调用委派到统一的ContextStrategy对象管理,客户端通过ContextStrategy来间接调用算法。策略模式的通用UML类图如下:
ContextStrategy角色:持有一个Strategy的引用,统一管理策略的调用
Strategy抽象策略角色:这是一个抽象角色,是基于面向对象设计原则考虑的,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的公共接口。
ConcreteStrategy具体策略角色:具体的算法或行为实现类
以我们日常生活的移动支付为例,我们常常在第三方APP中调用微信、支付宝、银联卡完成支付,接下来按步骤一步步实现
1、实现Strategy抽象策略
//从调用微信、支付宝、银联卡可以抽出一个公共的策略接口,同时也是为了实现定义中的互换
public interface PayStrategy {
public void pay(float money);
}
2、实现ContextStrategy角色
public class ContextStrategy {
private PayStrategy strategy;
public ContextStrategy(){
}
public void payout(float money){
strategy.pay(money);//调用策略
}
public void setStrategy(PayStrategy strategy){
this.strategy=strategy;//设置策略类
}
}
3、实现具体的策略
public class AliPayStrategy implements PayStrategy {
@Override
public void pay(float money) {
//调用支付宝的接口具体代码 略...
if(money<=200){
System.out.println("通过调用支付宝的接口"+"直接支付了"+money);
}else{
System.out.println("通过调用支付宝的接口"+"输入密码验证再支付了"+money);
}
}
}
public class WeChatPayStrategy implements PayStrategy {
@Override
public void pay(float money) {
//调用微信的接口略。。。。
System.out.println("通过调用微信支付的接口支付了"+money);
}
}
4、测试
public class MainStrategyClient {
public static void main(String[] args) {
ContextStrategy strategy=new ContextStrategy();
strategy.setStrategy(new AliPayStrategy());
strategy.payout(1000f);
strategy.setStrategy(new WeChatPayStrategy());
strategy.payout(20f);
}
}
四、结合简单工厂模式
其实设计模式之间的本质思想都是相通的,无非是继承、实现、多态的组合,所以有时候结合起来使用回让你的代码更具扩展性,这里结合简单工厂工模式实现也很简单,只需要把ContextStrategy角色改位工厂角色即可
package strategy;
//负责实例化对应产品的对象
public class Factory {
public static final String TYPE_ALI="ali";
public static final String TYPE_WECHAT="wechat";
private Factory() {
}
public static PayStrategy create(String type){
PayStrategy product=null;
if(TYPE_ALI.equals(type)){
product=new AliPayStrategy();
}else if(TYPE_WECHAT.equals(type)){
product=new WeChatPayStrategy();
}
return product;
}
}
使用的时候,直接通过工厂生成对应的策略
public class Client {
public static void main(String[] args) {
ContextStrategy strategy = new ContextStrategy();
strategy.setStrategy(new AliPayStrategy());
strategy.payout(1000f);
strategy.setStrategy(new WeChatPayStrategy());
strategy.payout(20f);
//结合简单工厂模式
PayStrategy payStrategy=Factory.create(Factory.TYPE_ALI);
payStrategy.pay(1000.0f);
payStrategy=Factory.create(Factory.TYPE_WECHAT);
payStrategy.pay(20.0f);
}
}