今天是一个特殊的日子,袁隆平院士没了,中午听到这个消息,心里很难受,能和牛人活在一个年代是我们的荣幸,我也不知道说啥,就是觉得袁老一辈子返璞归真,简简单单,那是我喜欢的状态,祝袁老一路走好!
之前读过程杰老师写的《大话设计模式》,但是在工作中好像并没有怎么使用,工作中我貌似就用过工厂模式,最近的业务本来是可以使用策略模式的,但是我没用,此处省略一万字。所以以后作者不得不发文章但是又觉得无话可说的时候,可能就抄一篇设计模式来勉强达到日更的目标,今天学一下策略模式。
策略模式(strategy):定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户。
在之前的文章中,我们说代码中的switch其实不太好,原因是switch会让代码局限在一个类型码上,所以在《重构》这本书中尽量采用策略模式和状态模式将对其改造。主要是将类型码的功能迁移到类中,换句话说就是要针对具体的case创建不同的类。但是考虑到每种case情况都具有类似的功能,因此可以将其共性的特点提取出来形成一个接口,具体的策略让具体的类去实现。
当具有策略的实现类的时候,我们最终代码还是有一个决策使用那种策略类,因此联系所有策略子类就成了工作类的任务,因此策略模式就变成如下所示:
这块为何要进行一个策略的包装类?相对来说我们其他业务在调用策略模式的时候如果跟策略模式base-strategy强绑定势必导致base-strategy的变动导致调用方很被动。因此这块的策略包装类将这个变动局限在一处从而使得局部代码的变动引起的整体改造变小,代价较低。当然我们也可以不用策略包装类进行聚合,但是为了策略的统一决策,那么势必就是采用状态值去决策,那么就是简单工厂模式与具体的策略的整合,注意这里不是策略模式,也就是简单工程模式+策略,在代码中为了让代码更加简洁,我们可以灵活使用构造方法。所以我们这里写个简单的例子:
接口:
public interface BaseStrategy {
int totalPrice = 0;
/**
* 测试策略模式
*/
void test();
}
策略A:
public class StrategyA implements BaseStrategy { /** * 测试A */ public void test() { System.out.println("策略A"); }}
策略B:
public class StrategyB implements BaseStrategy{ /** * 测试B */ public void test() { System.out.println("策略B"); }}
策略C:
public class StrategyC implements BaseStrategy{ /** * 测试C */ public void test() { System.out.println("策略C"); }}
策略包装类:
/** * 总领全局 */public class StrategyContent { /** * 引子 */ private BaseStrategy baseStrategy;
/** * 巧用构造函数,关联具体策略 */ public StrategyContent(int type){ switch (type){ case 1: baseStrategy=new StrategyA(); break; case 2: baseStrategy=new StrategyB(); break; case 3: baseStrategy=new StrategyC(); break; default: break; } }
/** * 总领调度 */ public void testStrategy(){ baseStrategy.test(); }}
上边的示例我们采用简单工厂和策略的直接嵌套,对于纯策略模式来说其实将具体的策略决策权放到了调用方。具体示例如下:
public class OriginStrategy { /** * 基础策略模式 */ BaseStrategy baseStrategy;
/** * 初始化 * @param baseStrategy */ OriginStrategy(BaseStrategy baseStrategy){ this.baseStrategy=baseStrategy; }
/** * 策略调用 */ public void test(){ this.baseStrategy.test(); }}
调用方:
public class TestStrategyContentMain { /** * 业务调用方 * @param args */ public static void main(String[] args) { OriginStrategy originStrategy; switch (1){ case 1: originStrategy=new OriginStrategy(new StrategyA()); break; case 2: originStrategy=new OriginStrategy(new StrategyB()); break; case 3: originStrategy=new OriginStrategy(new StrategyC()); break; default: throw new IllegalStateException("Unexpected value: " + 1); } originStrategy.test(); }}
在学完了策略模式之后,作者是觉得策略模式的一种更好实现是简单工厂模式+策略的实现,也就是将策略的具体决策隐藏,这样的好处就是说对于散落与业务中的分散调用来说更加容易修改。除此之外策略的增删也更加容易,对于代码来说变动也更加少一些。我们在工作中可以使用策略模式来处理类似多种业务场景。在spring编程框架中开发中我们要根据具体的状态码从ioc中获取具体的策略,那么我们就需要获取到spring上下文。需要实现的接口大概是applicationContentaWare。