策略模式
Strategy Pattern:策略模式是GoF23中设计模式中属于行为型设计模式的一种。
策略模式的关键点就在于策略两字,策略是一种方法,一种方式,一种计策。用术语来讲的话,可以将其理解为算法,不同的策略也就是不同的算法。
策略模式的作用呢,就是使得用户在执行某个操作的时候得到一个结果,而这个结果可能是由不同的算法所得到的,但是用户并不知道这些,算法的改变影响不到用户自己对这个功能的使用。
结构
可以看到上图是一个对于策略模式来说一个简单的类图,可以看到有着三个角色:
- 策略抽象类:这个角色仅仅是将所有的策略进行了一个抽象而已(当然,你也可以定义一个接口带代替抽象类)
- 算法实现类:这个角色就是具体的策略,也可以说是具体的算法的逻辑实现了。
- 配置类:也可以说是环境类,这个是给用户调用的,里面维护者一个策略对象,用来通过用户的需求选择执行特定的算法。
举例说明
- 策略两字一出,最先想到的估摸着就是“锦囊妙计”啦,诸葛亮在刘备去江东的时候就给了赵云三个锦囊妙计,特定的时候需要取出一个特定的锦囊,这也是策略模式的一种体现。
- 贴近我们生活的就是例子就是出行了,在自己待着的一个城市去往另一个城市,是坐汽车呢,做火车呢,做高铁呢,做飞机呢,还是说自驾行或者直接来个11路公交车去?都可以的,这也是策略模式的一种体现。
- 最容易体现的就是限制点外卖的各种商家的优惠卷了,打折的优惠券,满减的优惠券,直减的优惠券,等等。这种类型在最后计算实际的金额的时候,就是需要使用不同的算法来实现,这个例子更能体现出策略模式的意义了。
注意
-
通过上面的例子,其实我们可以发现,这不就是多条件的选择吗?可以使用if-else条件分支啊,还可以通过switch语句不是更加的实现简单?
但是,需要注意的是,通过if-else或switch语句编写出来的代码,虽然可以得到正确的效果,但是仅仅是当前的效果,如果忽然出现了一个新的需求,那岂不是要去改源码,这显然违犯了开闭原则,而策略模式可以规避这一点,使得程序具有扩展性。
-
策略模式的一个缺点就是所有的策略应该是需要用户知道的,不能仅仅想诸葛亮一样直接给藏了起来,赵云完全不知道里面的东西,但是也不是完全不知道,起码赵云知道什么时候用哪一个。
也就是说,对于所有的策略,需要完全暴露给用户,使得用户自己选择通过使用哪个策略才行。
-
策略的定义,也需要有抽象的概念,比如满300减100的优惠券和满1000减300的优惠券应该是算作是一种策略;再说打五折和打七折都是打折,这也是一样的策略,只是具体的数字不同而已。
一个小DEMO
-
场景
写个简单的Demo,体现出策略模式的使用规则。嗯,就比如说我们平常上班吧,有的朋友是骑着共享单车去上班的,有的是挤着满满的人的公交,也有的是地铁公交一起来,笔者还算不错,可以直接走着去,沿途还可以看看风景呢。
-
首先定义个顶层抽象的策略接口吧
package com.strategy; /** * 策略模式——策略抽象接口 * @author WQ */ public interface IStrategy { /** * 定义个方法,显示出各种策略选择的不同 */ void show(); }
-
创建各种不同的策略了,这里就是骑自行车,公交,和走路吧,简单一点点
package com.strategy; /** * 策略模式——实际策略——自行车 * @author WQ */ public class Bicycle implements IStrategy{ @Override public void show() { System.out.println("Go to work by bike!"); } } //--------------------------------------------------------------- package com.strategy; /** * 策略模式——实际策略——公交车 * @author WQ */ public class Bus implements IStrategy{ @Override public void show() { System.out.println("Go to work by bus"); } } //------------------------------------------------------------------ package com.strategy; /** * 策略模式——实际策略——步行 * @author WQ */ public class Walk implements IStrategy { @Override public void show() { System.out.println("Walk to work!"); } }
-
写一个配置类(也可以叫环境类,也可以叫用户需要调用的类,都可以)
package com.strategy; /** * 策略模式——上下文配置类/环境类 * @author WQ */ public class Context { /** * 需要注意的就是,这个类需要维护一个抽象策略对象 * 因为这个类需要指定具体的策略,才能进行使用 */ private IStrategy strategy; /** * 加个setter,用于实时改变策略 * @param strategy */ public void setStrategy(IStrategy strategy) { this.strategy = strategy; } /** * 通过构造函数定义策略,这里使用IStrategy 可以实现多态的特性 * @param strategy */ public Context(IStrategy strategy) { this.strategy = strategy; } /** * 这里就是使用方法的位置, * 用户只需要通过指定的策略创建这个类,调用这个方法进行实际的调用即可 */ public void work() { this.strategy.show(); } }
-
加个测试类
package com.strategy; /** * 策略模式——测试类部分 * @author WQ */ public class Main { public static void main(String[] args) { /** * 用户需要的创建自己想要的策略 * 然后使用这个策略创建配置类进行方法的调用。 */ Context context = new Context(new Bicycle()); context.work(); context.setStrategy(new Bus()); context.work(); context.setStrategy(new Walk()); context.work(); } }
-
测试走一波
Go to work by bike! Go to work by bus Walk to work!
完成!