策略模式

if...else...的优雅写法,可以配合委托模式一起使用

  • 定义:定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户
  • 补充定义:处理大量if...else...代码
  • 类型:行为型
  • 适用场景:
    • 系统有很多类,而他们的区别仅仅在于他们的行为策略不同
    • 一个系统需要动态地在几种算法中选择一种
  • 优点:
    • 符合开闭原则
    • 避免使用多重条件转移语句
    • 提高算法的保密性和安全性
  • 缺点:
    • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类
    • 产生很多策略类
  • 相关设计模式
    • 策略模式和工厂模式:工厂模式是创建型的,策略模式是行为型的,工厂模式接收指令创建符合要求的实例对象,而策略模式接收创建好的对象从而实现不同的行为
    • 策略模式和状态模式:对于策略模式客户端需要知道到底选择哪个策略,而在使用状态模式时客户端不需要关心具体的状态,它的这些状态会自动装换

公式计算

/**
 * <p>定义计算接口,提供根据公式(字符串)计算值的方法</p>
 *
 */
public interface ICalculator {

    /**
     * <p>根据公式字符串,计算得出值</p>
     *
     * @param formula 公式
     * @return*/
    double calculate(String formula);

}
/**
 * <p>乘法运算实现乘法公式的结果计算</p>
 *
 */
public class Mul implements ICalculator {

    @Override
    public double calculate(String formula) {
        double[] valArray = CalculatorHelper.getValArray(formula, "\\*");
        return valArray[0] * valArray[1];
    }

}
/**
 * <p>加法运算实现加法公式的结果计算</p>
 *
 */
public class Plus implements ICalculator {

    @Override
    public double calculate(String formula) {
        double[] valArray = CalculatorHelper.getValArray(formula, "\\+");
        return valArray[0] + valArray[1];
    }

}
/**
 * <p>减法运算实现减法公式的结果计算</p>
 *
 */
public class Sub implements ICalculator {

    @Override
    public double calculate(String formula) {
        double[] valArray = CalculatorHelper.getValArray(formula, "-");
        return valArray[0] - valArray[1];
    }

}
/**
 * <p>计算辅助类,主要提取公式中的数数组</p>
 *
 */
public class CalculatorHelper {

    public static double[] getValArray(String formula, String splitChar) {
        //记得消除空格
        String array[] = formula.trim().split(splitChar);
        double arrayDouble[] = new double[2];
        arrayDouble[0] = Double.parseDouble(array[0]);
        arrayDouble[1] = Double.parseDouble(array[1]);
        return arrayDouble;
    }

}

 

UML

商场打折

/**
 * <p>定义价格计算策略接口,为每一个策略类提供统一的计算折扣价钱的方法</p>
 *
 */
public interface ICalculatePrice {

    /**
     * <p>根据商品的实际总价计算得到商品折后的价钱</p>
     *
     * @param totalPrice 实际商品总价
     * @return 折后价
     */
    double getDiscountedPrice(double totalPrice);

}
/**
 * <p>电商节 - 6.18 -- 满618元减99,满1000元打8.5折</p>
 *
 */
public class DianShang618 implements ICalculatePrice {

    @Override
    public double getDiscountedPrice(double totalPrice) {

        if (totalPrice >= 618) {
            return totalPrice - 99;
        }

        if (totalPrice >= 1000) {
            return totalPrice * 0.85;
        }

        return totalPrice;
    }

}
/**
 * <p>商品满减活动 -- 满300元减100元</p>
 *
 */
public class Man300Jian100 implements ICalculatePrice {

    @Override
    public double getDiscountedPrice(double totalPrice) {

        // 全场消费满300元,减100元
        if (totalPrice >= 300) {
            return totalPrice - 100;
        }
        return totalPrice;
    }

}
/**
 * <p>天猫双11购物狂欢节 -- 满500减少166,满1000元随机打折,有可能免单哦</p>
 *
 */
public class Shuang11 implements ICalculatePrice {

    // 分别是免单、6.5折、7.5折、8.5折和9折
    private static double[] discount = new double[]{0.0, 0.65, 0.75, 0.85, 0.90};

    @Override
    public double getDiscountedPrice(double totalPrice) {

        if (totalPrice >= 500 && totalPrice < 1000) {
            return totalPrice - 166;
        }

        if (totalPrice >= 1000) {
            Random random = new Random();
            return totalPrice * (discount[random.nextInt(5)]);
        }
        return 0;
    }

}
/**
 * <p>价格上下文类</p>
 * <p>对用户暴露计算折后价钱的方法,由用户选择使用具体的打折策略类来计算最终的商品价钱</p>
 *
 */
public class PriceContext {

    private ICalculatePrice price;

    public PriceContext(ICalculatePrice price) {
        this.price = price;
    }

    public double discount(double totalPrice) {
        double discountedPrice = price.getDiscountedPrice(totalPrice);
        if (0.0 == discountedPrice) {
            System.out.println("恭喜您,您本次消费免单!");
        }
        return discountedPrice;
    }

}

 

UML

测试

/**
 * <p>策略模式测试</p>
 *
 */
public class StrategyTest {

    public static void main(String[] args) {

        // 1、 策略模式☞运算公式结果计算
        plus();
        sub();
        mul();

        // 2、 策略模式☞商场打折
        man300jian100();
        dianShang618();
        shuang11();
    }

    private static void plus() {
        System.out.println("===============2+ 8 乘法运算");
        ICalculator calculator = new Plus();
        double calculate = calculator.calculate("2+ 8");
        System.out.println("2+ 8 = " + calculate);
    }

    private static void sub() {
        System.out.println("===============2 - 8 减法运算");
        ICalculator calculator = new Sub();
        double calculate = calculator.calculate("2 - 8");
        System.out.println("2 - 8 = " + calculate);
    }

    private static void mul() {
        System.out.println("===============2*8 乘法运算");
        ICalculator calculator = new Mul();
        double calculate = calculator.calculate("2*8");
        System.out.println("2*8 = " + calculate);
    }

    private static void man300jian100() {

        System.out.println("===============全场满300减100!");
        double totalPrice = 450.0;
        System.out.println("商品原价:" + totalPrice + "¥");
        PriceContext price = new PriceContext(new Man300Jian100());
        System.out.println("商品折后的价钱:" + price.discount(totalPrice) + "¥");

    }

    private static void dianShang618() {

        System.out.println("===============电商节6.18欢快购!");
        double totalPrice = 700.0;
        System.out.println("商品原价:" + totalPrice + "¥");
        PriceContext price = new PriceContext(new DianShang618());
        System.out.println("商品折后的价钱:" + price.discount(totalPrice) + "¥");

        totalPrice = 1024.0;
        System.out.println("商品原价:" + totalPrice + "¥");
        System.out.println("商品折后的价钱:" + price.discount(totalPrice) + "¥");
    }

    private static void shuang11() {

        System.out.println("===============双11全场嗨翻购!");
        double totalPrice = 623.0;
        System.out.println("商品原价:" + totalPrice + "¥");
        PriceContext price = new PriceContext(new Shuang11());
        System.out.println("商品折后的价钱:" + price.discount(totalPrice) + "¥");

        totalPrice = 1500.0;
        System.out.println("商品原价:" + totalPrice + "¥");
        System.out.println("商品折后的价钱:" + price.discount(totalPrice) + "¥");
    }


    /**
     *
     * 百科上如此介绍策略模式:
     * 策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。
     * 策略模式让算法独立于使用它的客户而独立变化。
     *
     * 通过上述两个算法计算的例子,我们可以领略到策略模式的好处:
     * (1)用户或算法使用者可以选择不同的算法类来实现自己业务算法的需要
     * (2)开发者扩展新的算法类,只需要新建一个类实现calculate方法即可,扩展相当方便
     * (4)总结就是,遵守了"开闭原则",对扩展开放,对修改关闭!
     * 缺点:
     * (1)如果基于选择的策略模式很多的话,这就意味着子类有很多,维护起来增加复杂性
     * (2)对于使用者来说,他必须知道全部的策略类,才可以做到策略的任意切换
     */

}
============运行结果===============
===============2+ 8 乘法运算
2+ 8 = 10.0
===============2 - 8 减法运算
2 - 8 = -6.0
===============2*8 乘法运算
2*8 = 16.0
===============全场满300减100!
商品原价:450.0¥
商品折后的价钱:350.0===============电商节6.18欢快购!
商品原价:700.0¥
商品折后的价钱:601.0¥
商品原价:1024.0¥
商品折后的价钱:925.0===============双11全场嗨翻购!
商品原价:623.0¥
商品折后的价钱:457.0¥
商品原价:1500.0¥
恭喜您,您本次消费免单!
商品折后的价钱:0.0¥

 

源码中的应用

  • java.util.Comparator:这个比较器就是一个抽象的策略,它提供了compare()和equals()方法,所有的策略都要实现这两个方法,它内部还有一堆具体的策略可供使用
public interface Comparator<T> {
    ...
    int compare(T o1, T o2);
    ...
    boolean equals(Object obj);
    ...
}

 

posted @ 2024-01-23 15:28  wangzhilei  阅读(2)  评论(0编辑  收藏  举报