设计模式:策略模式的设计及应用场景优化方式Java版

开篇

今天我们来讨论一下设计模式中最常用的一种行为模式----策略模式,在实际的项目中,我们经常会解决类似这样的业务场景,比如,对于同一件事情,在不同时间或不同状态下,执行不同的逻辑,我们就可以通过策略模式来封装具体的算法规则,实际使用模块只需要知道使用何种策略即可,今天我们就通过两个数的运算来模拟多规则下策略模式如何设计并改善。

基本介绍

策略模式(Strategy Pattern)中,定义出一套算法族,让他们可以根据不同场景进行替换,同时通过定义配置对象来对外提供相应的算法对象。目的是解决多场景下,核心处理逻辑类似,判断语句过多的问题。

主要解决

  1. 通过if----else判断将不同类型的业务逻辑聚合在一起时,维护成本增高,耦合性高,可读性低。
  2. 所有逻辑糅合在一起,当有一处发生变化时,带动全体一起修改。
  3. 不能进行单元测试,或单元测试不便捷。

关键代码

  1. 封装算法接口。
  2. 多种算法类实现总接口。
  3. 提供配置对象给客户端调用算法类。

应用场景

  1. 本文案例,根据不同类型,对两个数执行不同运算逻辑。
  2. 不同时间段,商场开展不同促销活动。
  3. 旅行出游,选择不同交通工具,前往目的地。

优点

  1. 实际的算法和使用算法类直接耦合性减少。
  2. 减少大量的判断逻辑,将不同逻辑拆开,便于维护。
  3. 简化单元测试,可以针对性对某一策略进行测试和维护。

缺点

  1. 场景增多时,策略类会增多,造成类膨胀。
  2. 还是需要通过判断来寻找到具体策略。
  3. 算法实现类超过4个时,需要使用组合模式。

案例

给定两个数,num1,num2,分别计算加减乘除。

1、定义逻辑处理总接口

/**
 * 数据计算接口
 * 优点
 * 定义数据计算的统一接口,
 * 便于后续使用时不关心每个类中具体方法的定义,
 * 实现类可以实现多个接口,因此此处不用抽象类。
 * 缺点
 * 1、该接口存在多个方法,而后续操作有些不适用,就需要实现很多无用方法,增加代码量。
 * 2、当接口类中增加一个新的方法时,实现类必须全体一起增加该方法的实现。
 */
public interface CalculationInterface {
    //用于处理两个数的运算
    public int mathod(int num1, int num2);
}

2、实现加减乘除算法类

/**
 * 数据处理实现:加法策略实现类
 */
public class Addition implements CalculationInterface {
    /**
     * @param num1 数据1
     * @param num2 数据2
     * @return 两数之和
     */
    @Override
    public int mathod(int num1, int num2) {
        return num1 + num2;
    }
}
/**
 * 数据处理实现:减法策略实现类
 */
public class Subtraction implements CalculationInterface {
    /**
     * @param num1 数据1
     * @param num2 数据2
     * @return 两数相减
     */
    @Override
    public int mathod(int num1,int num2) {
        return num1 - num2;
    }
}
/**
 * 数据处理实现:乘法策略实现类
 */
public class Multiplication implements CalculationInterface {
    /**
     * @param num1 数据1
     * @param num2 数据2
     * @return 两数相乘
     */
    @Override
    public int mathod(int num1, int num2) {
        return num1 * num2;
    }
}
/**
 * 数据处理实现:除法策略实现类
 */
public class Division implements CalculationInterface {
    /**
     * @param num1 数据1
     * @param num2 数据2 不可以为0
     * @return 两数相除
     */
    @Override
    public int mathod(int num1, int num2) {
        if (num2 == 0) throw new RuntimeException("除数不能为0");
        return num1 / num2;
    }
}

3、构建配置对象

/**
 * 提供配置环境
 * 统一策略的创建,
 * 统一策略方法的使用,
 * 对外不需要关心具体策略内部如何实现,
 * 不需要关心如何创建相关策略类,执行相应策略的方式,
 * 只需要知道有哪些策略,该使用哪一策略。
 */
public class Context {
    private CalculationInterface anInterface;

    //通过统一配置环境,创建不同策略实现类。
    public Context(CalculationInterface anInterface) {
        this.anInterface = anInterface;
    }

    //提供参数统一入口,根据创建不同的实现类,执行不同策略,
    public int logic(int num1, int num2) {
        return anInterface.mathod(num1, num2);
    }

}

4、策略模式执行类

/**
 * 策略模式测试
 */
public class StrategyTest {
    public static void main(String[] args) {
        int add = 0, sub = 0, mul = 0, div = 0;
        if (StrategyType.getAdd().equals("加")) {
            Context addition = new Context(new Addition());
            add = addition.logic(400, 200);
        }
        if (StrategyType.getSub().equals("减")) {
            Context subtraction = new Context(new Subtraction());
            sub = subtraction.logic(400, 200);
        }
        if (StrategyType.getMul().equals("乘")) {
            Context multiplication = new Context(new Multiplication());
            mul = multiplication.logic(400, 200);
        }
        if (StrategyType.getDiv().equals("除")) {
            Context division = new Context(new Division());
            div = division.logic(400, 200);
        }
        System.out.println("加:" + add + " 减:" + sub + " 乘:" + mul + " 除:" + div);
    }
}

5、定义策略类型

/**
 * 定义策略类型
 */
public class StrategyType {
    private static final String add = "加";
    private static final String sub = "减";
    private static final String mul = "乘";
    private static final String div = "除";

    public static String getAdd() {
        return add;
    }

    public static String getSub() {
        return sub;
    }

    public static String getMul() {
        return mul;
    }

    public static String getDiv() {
        return div;
    }
}

以上就是策略模式的具体使用方式,但是我们不难发现,还是需要客户端去判断不同类型下,如何创建,不仅比较繁琐,同时还需要知道具体策略才行,这对客户端来说要求太高了。

改进:策略+简单工厂模式

我们将客户端判断部分封装到配置类中,这样客户端不需要关心何种类型下如何实现对应算法,只需要实现配置类即可,简化操作。

1、改进配置类

/**
 * 配置类改善
 * 原因
 * 使用策略模式后,客户端依然需要判断在具体条件下,创建具体的策略,因此改造配置类
 * 将判断创建具体策略的行为从客户端隔离,让客户端彻底不再判断
 * 方案
 * 创建具体策略时传入相关类型,交给配置类进行判断
 */
public class ContextImprove {
    private CalculationInterface anInterface;

    //通过统一配置环境,创建不同策略实现类。
    public ContextImprove(String strategyType) {
        if (strategyType.equals("加")) {
            this.anInterface = new Addition();
        }
        if (strategyType.equals("减")) {
            this.anInterface = new Subtraction();
        }
        if (strategyType.equals("乘")) {
            this.anInterface = new Multiplication();
        }
        if (strategyType.equals("除")) {
            this.anInterface = new Division();
        }

    }

    //提供参数统一入口,根据创建不同的实现类,执行不同策略,
    public int logic(int num1, int num2) {
        return anInterface.mathod(num1, num2);
    }
}

2、测试

/**
 * 策略模式测试
 */
public class StrategyTest {
    public static void main(String[] args) {
        ContextImprove contextImprove = new ContextImprove(StrategyType.getAdd());
        System.out.println(StrategyType.getAdd() + ":" + contextImprove.logic(100, 200));
    }
}

此时我们可以看到,客户端使用时根本不需要关心如何创建相应的算法类,只需要创建配置类即可,但是不难发现上面依然存在很多判断在配置类中,这里可以用抽象工厂来替换掉,本文不做叙述,大家可以自行研究。

总结

  1. 在处理业务需求时,如果针对同一事情,在不同场景下进行不同操作,我们可以使用策略模式减少耦合性。
  2. 策略模式的使用可以让单元测试更加的便捷。
  3. 实际业务中,我们往往通过组合模式来解决问题,掌握核心设计模式的同时,还要灵活辅助其他模式。

 

你可能感兴趣的:(要优雅--设计模式,java,设计模式,程序人生,经验分享)