策略模式

composed 2019年12月05日 144次浏览

策略模式

定义

  策略模式定义了一系列的算法,并将每一个算法封装起来,使每个算法可以相互替代,使算法本身和使用算法的客户端分割开来,相互独立。

结构

  1. 策略接口角色 IStrategy: 用来约束一系列具体的策略算法,策略上下文角色 ConcreteStrategy 使用此策略接口来调用具体的策略所实现的算法。

  2. 具体策略实现角色 ConcreteStrategy: 具体的策略实现,即具体的算法实现。

  3. 策略上下文角色 StrategyContext: 策略上下文,负责和具体的策略实现交互,通常策略上下文对象会持有一个真正的策略实现对象,策略上下文还可以让具体的策略实现从其中获取相关数据,回调策略上下文对象的方法。

    UML 类图:

    策略

UML 序列图:

策略序列图

现在需求是收银,根据不同的类型采取相应的收银策略(返现,折扣)

原始写法

@Slf4j
public class market {

    private BigDecimal total = new BigDecimal("0.0");

    private void calculateTotalPrice(BigDecimal goodsPrice, BigDecimal goodsNum, String discount) {

        BigDecimal totalPrice = goodsPrice.multiply(goodsNum);
        // 打折
        total = discountPrice(totalPrice, discount);
        log.info("===============================");
        log.info("单价:" + goodsPrice + "  数量:" + goodsNum + "  合计:" + total);
        log.info("===============================");

    }

    /**
     * 打折后的价格
     *
     * @param totalPrice
     * @param discount
     * @return BigDecimal total
     */
    private BigDecimal discountPrice(BigDecimal totalPrice, String discount) {
        totalPrice = totalPrice.multiply(new BigDecimal(discount));
        return total.add(totalPrice);
    }

    /**
     *折扣选择
     *
     * @param scan
     * @return String discount
     */
    private static String getDiscount(Scanner scan) {
        int count = scan.nextInt();
        String discount = null;
        switch (count) {
            case 1:
                discount = "0.8";
            case 2:
                discount = "0.5";
            case 3:
                discount = "0.3";
            default:
        }
        return discount;
    }

    public static void main(String[] args) {

        Scanner scan = new Scanner(System.in);
        System.out.print("请输入单价:");
        String price = scan.nextLine();
        System.out.print("请输入数量:");
        String num = scan.nextLine();
        System.out.println("请选择折扣:1、八折  2、五折  3、三折");
        String discount = getDiscount(scan);

        market market = new market();
        market.calculateTotalPrice(new BigDecimal(price), new BigDecimal(num), discount);
    }

}

下面是策略模式

策略抽象类

public abstract class CashSuperStrategy {

    /**
     * 收取现金
     *
     * @param money 原价
     * @return BigDecimal 打折后价格
     */
    public abstract BigDecimal acceptCash(BigDecimal money);
}

具体策略一

public class ConcreteStrategyOne extends CashSuperStrategy {

    /**
     * 具体算法实现
     * @param money 原价
     * @return result 折扣后价格
     */
    @Override
    public BigDecimal acceptCash(BigDecimal money) {
        return money;
    }
}

具体策略二

public class ConcreteStrategyTwo extends CashSuperStrategy {

    /**
     * 输入金额
     */
    private BigDecimal moneyCondition;

    /**
     * 返利金额
     */
    private BigDecimal moneyReturn;

    ConcreteStrategyTwo(BigDecimal moneyCondition, BigDecimal moneyReturn) {
        this.moneyCondition = moneyCondition;
        this.moneyReturn = moneyReturn;
    }

    /**
     * 具体策略实现
     * @param money 原价
     * @return result 折扣后价格
     */
    @Override
    public BigDecimal acceptCash(BigDecimal money) {
        BigDecimal result = money;
        if (money.compareTo(moneyCondition) != -1) {
            result = money.subtract(moneyReturn);
        }
        return result;
    }
}

具体策略三

public class ConcreteStrategyThree extends CashSuperStrategy {

    /**
     * 折扣率
     */
    private BigDecimal moneyRebate;

    /**
     * 初始化时带入折扣率
     */
    ConcreteStrategyThree(String moneyRebate) {
        this.moneyRebate = new BigDecimal(moneyRebate);
    }

    /**
     *
     * @param money 原价
     * @return result 折扣后价格
     */
    @Override
    public BigDecimal acceptCash(BigDecimal money) {
        return money.multiply(moneyRebate);
    }
}

上下文

@Slf4j
public class CashContext {

    private CashSuperStrategy cashSuperStrategy;

    public CashContext(int type) {
        switch (type) {
            case 1:
                cashSuperStrategy = new ConcreteStrategyOne();
                log.info("当前没有活动");
                break;
            case 2:
                cashSuperStrategy = new ConcreteStrategyTwo(new BigDecimal("300"),new BigDecimal("100"));
                log.info("当前活动为:满300减100");
                break;
            case 3:
                cashSuperStrategy = new ConcreteStrategyThree("0.8");
                log.info("当前活动为:打八折");
                break;
            default:
        }
    }

    public BigDecimal getResult(BigDecimal money) {
        return cashSuperStrategy.acceptCash(money);
    }

}

测试类

@Slf4j
public class market {

    private static BigDecimal total = new BigDecimal("0.0");

    public static void main(String[] args) {

        Scanner scan = new Scanner(System.in);
        System.out.println("请输入活动类型:1、正常收费  2、满300减100  3、打八折");
        int type = scan.nextInt();
        System.out.print("请输入单价:");
        String goodsPrice = scan.next();
        System.out.print("请输入数量:");
        String goodsNum = scan.next();

        CashContext cashContext = new CashContext(type);
        BigDecimal totalPrice = cashContext.getResult(new BigDecimal(goodsPrice)).multiply(new BigDecimal(goodsNum));

        total = total.add(totalPrice);
        log.info("===============================");
        log.info("单价:" + goodsPrice + "  数量:" + goodsNum + "  合计:" + total);
        log.info("===============================");

    }

}

参考资料: https://blog.csdn.net/tugangkai/article/details/88074288