在开发中经常遇到这种情况,实现某个功能有多种算法策略,我们可以根据不同环境或者条件选择不同的算法策略来完成该功能,比如查找、排序等,一种常用方式是硬编码在一个类中,如需要提供多种查找算法,可以将这些算法写到一个类中,在该类中提供多个方法,每一个方法对应一个具体的查找算法;当然也可以将这些查找算法封装在一个统一的方法中,通过 if-else 或者 case 等条件判断语句来进行选择。但是如果需要增加新的算法策略,就需要修改封装算法类的源代码;更换查找算法,也需要修改客户端的调用代码。并且在这个类中封装了大量算法,也会使得该类代码较复杂,维护较为困难。如果我们将这些策略包含在客户端,这种做法更不可取,将导致客户端程序庞大而且难以维护,如果存在大量可供选择的算法时问题将变得更加严重。
如何让算法和对象分开来,使得算法可以独立于使用它的客户而变化?解决方法就是使用策略模式。
将类中经常改变或者可能改变的部分提取为作为一个抽象策略接口类,然后在类中包含这个对象的实例,这样类实例在运行时就可以随意调用实现了这个接口的类的行为。
比如定义一系列的算法,把每一个算法封装起来,并且使它们可相互替换,使得算法可独立于使用它的客户而变化,这就是策略模式。
(1)环境类(Context):通过 ConcreteStrategy 具体策略类来配置,持有 Strategy 对象并维护对Strategy 对象的引用。可定义一个接口来让 Strategy 访问它的数据。
(2)抽象策略类(Strategy):定义所有支持的算法的公共接口。 Context使用这个接口来调用某ConcreteStrategy 定义的算法。
(3)具体策略类(ConcreteStrategy): Strategy 接口的具体算法。
促销活动。
- public class CuXiaoContext {
-
- private CuXiao cuXiao;
-
- public CuXiaoContext(CuXiao cuXiao) {
- this.cuXiao = cuXiao;
- }
- //定义一个使用算法的方法
- public void use(){
- cuXiao.cuxiao();
- }
- }
- public interface CuXiao {
- void cuxiao();
- }
- public class SuanFa618 implements CuXiao {
-
- @Override
- public void cuxiao() {
- System.out.println("使用6.18的促销算法");
- }
- }
- public class SuanFa1111 implements CuXiao{
-
- @Override
- public void cuxiao() {
- System.out.println("使用11.11的促销算法");
- }
- }
- public class SuanFa1212 implements CuXiao{
-
- @Override
- public void cuxiao() {
- System.out.println("使用12.12的促销算法");
- }
- }
- public class CuXiaoTest {
-
- public static void main(String[] args) {
- //SuanFa618 suanFa618 = new SuanFa618();
- SuanFa1111 suanFa1111 = new SuanFa1111();
- CuXiaoContext context = new CuXiaoContext(suanFa1111);
- context.use();
- }
- }
策略模式优缺点:
优点:
1、算法可以自由切换(策略类自由切换)。
2、避免使用多重条件判断。
3、扩展性良好(符合开闭原则)。
缺点:
1、策略类会增多。
2、所有策略类都需要对外暴露。
3、客户端必须知道所有的策略类,才能确定要调用的策略类。
策略模式使用场景:
如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
一个系统需要动态地在几种算法中选择一种。
如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。