用一个营销策略的实例说清楚策略模式的应用场景

一、背景

  • 作为一个开发人员,需要掌握面向对象开发各种基础知识,同时也需要了解各种设计原则与设计模式;熟练掌握设计模式,可以让我们开发出复用高,扩展性强、易于维护的系统。
  • 掌握设计模式的理论知识不难,难就难在怎么在实际项目中具体应用,或者说哪个应用场景适合应用哪个设计模式。
  • 本文将通过一个实际的营销策略例子来说明策略模式的具体适用场景

二、策略模式

  • 策略模式(Strategy Pattern)是一种比较简单的设计模式,其核心思想是定义算法族,分别封装起来,让它们之间可以互相替换。背后的设计原则是:①封装变化;②多用组合,少用继承;③针对接口编程,不针对实现编程。
  • 我们将举营销策略中订单折扣的例子来说明:
  1. 公司会在每个季度根据市场情况推出各种营销策略
  2. 客户下单时享受公司正在执行的营销策略,形成订单折扣
    在这里插入图片描述

2.1 未用设计模式

  • 为了做比较,我们看下未用设计模式的例子是怎么样的:
  1. 创建一个客户类
/**
 * 客户
 *
 * @author zhuhuix
 * @date 2021-03-19
 */
public class Customer {

    // 客户编号
    private String customerCode;

    // 客户名称
    private String customerName;

    // 客户级别 -- 例子中以A,B,C区分
    private String customerClass;

    public Customer(String customerCode, String customerName, String customerClass) {
        this.customerCode = customerCode;
        this.customerName = customerName;
        this.customerClass = customerClass;
    }

    public String getCustomerCode() {
        return customerCode;
    }

    public void setCustomerCode(String customerCode) {
        this.customerCode = customerCode;
    }

    public String getCustomerName() {
        return customerName;
    }

    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }

    public String getCustomerClass() {
        return customerClass;
    }

    public void setCustomerClass(String customerClass) {
        this.customerClass = customerClass;
    }
}

  1. 创建一个订单类
/**
 * 订单
 *
 * @author zhuhuix
 * @date 2021-03-19
 */
public class Order {

    // 客户
    private Customer customer;

    // 产品
    private String product;

    // 数量
    private BigDecimal num;

    // 单价
    private BigDecimal price;

    // 折扣
    private BigDecimal discount;

    // 金额
    private BigDecimal amount;

    // 实际金额
    private BigDecimal actualAmount;

    public Order(Customer customer, String product, BigDecimal num, BigDecimal price) {
        this.customer = customer;
        this.product = product;
        this.num = num;
        this.price = price;
        this.amount = num.multiply(price);
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    public String getProduct() {
        return product;
    }

    public void setProduct(String product) {
        this.product = product;
    }

    public BigDecimal getNum() {
        return num;
    }

    public void setNum(BigDecimal num) {
        this.num = num;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    public BigDecimal getDiscount() {
        return discount;
    }

    public void setDiscount(BigDecimal discount) {
        this.discount = discount;
        this.actualAmount = num.multiply(price).multiply(discount);
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public void setAmount(BigDecimal amount) {
        this.amount = amount;
    }

    public BigDecimal getActualAmount() {
        return actualAmount;
    }

    public void setActualAmount(BigDecimal actualAmount) {
        this.actualAmount = actualAmount;
    }

    @Override
    public String toString() {
        return "Order{" +
                "customer=" + customer.getCustomerName() +
                ", product='" + product + '\'' +
                ", num=" + num +
                ", price=" + price +
                ", discount=" + discount +
                ", amount=" + amount +
                ", actualAmount=" + actualAmount +
                '}';
    }
}
  1. 设计一个营销策略,形成订单折扣
/**
 * 销售订单应用营销策略进行打折
 *
 * @author zhuhuix
 * @date 2021-03-19
 */
public class Sales {

    public static void main(String[] args) {

        // 创建客户
        Customer customer1 = new Customer("001","上海客户","A");
        Customer customer2 = new Customer("002","北京客户","B");
        Customer customer3 = new Customer("003","广州客户","C");
        Customer customer4 = new Customer("004","深圳客户","D");

        // 创建订单
        Order order1 = new Order(customer1,"产品", BigDecimal.valueOf(1000),BigDecimal.valueOf(10.5));
        Order order2 = new Order(customer2,"产品", BigDecimal.valueOf(2000),BigDecimal.valueOf(10.5));
        Order order3 = new Order(customer3,"产品", BigDecimal.valueOf(3000),BigDecimal.valueOf(10.5));
        Order order4 = new Order(customer4,"产品", BigDecimal.valueOf(4000),BigDecimal.valueOf(10.5));

        // 计算折扣
        order1.setDiscount(calcDiscount1(customer1.getCustomerClass()));
        order2.setDiscount(calcDiscount1(customer2.getCustomerClass()));
        order3.setDiscount(calcDiscount1(customer3.getCustomerClass()));
        order4.setDiscount(calcDiscount1(customer4.getCustomerClass()));

        System.out.println(order1.toString());
        System.out.println(order2.toString());
        System.out.println(order3.toString());
        System.out.println(order4.toString());

    }

    // 根据客户级别分别给予折扣
    // A类客户,打八折;B类客户,打九折;C类客户,打95折
    private static BigDecimal calcDiscount1(String customerClass){
        switch (customerClass){
            case "A":
                return BigDecimal.valueOf(0.8);
            case "B":
                return BigDecimal.valueOf(0.9);
            case "C":
                return BigDecimal.valueOf(0.95);
            default:
                return BigDecimal.valueOf(1);
        }
    }    
}

  • 根据客户级别计算出了订单的折扣
    在这里插入图片描述
  • 以上的代码看起来简单明了,但公司的营销策略是动态变化的,到了下季度,营销策略变成了按订单下单量的多少来进行打折,那我们需要对程序做以下修补:
/**
 * 销售订单应用营销策略
 *
 * @author zhuhuix
 * @date 2021-03-19
 */
public class Sales {

    public static void main(String[] args) {

        // 创建客户
        Customer customer1 = new Customer("001","上海客户","A");
        Customer customer2 = new Customer("002","北京客户","B");
        Customer customer3 = new Customer("003","广州客户","C");
        Customer customer4 = new Customer("004","深圳客户","D");

        // 创建订单
        Order order1 = new Order(customer1,"产品", BigDecimal.valueOf(1000),BigDecimal.valueOf(10.5));
        Order order2 = new Order(customer2,"产品", BigDecimal.valueOf(2000),BigDecimal.valueOf(10.5));
        Order order3 = new Order(customer3,"产品", BigDecimal.valueOf(3000),BigDecimal.valueOf(10.5));
        Order order4 = new Order(customer4,"产品", BigDecimal.valueOf(4000),BigDecimal.valueOf(10.5));

        // 计算折扣
//        order1.setDiscount(calcDiscount1(customer1.getCustomerClass()));
//        order2.setDiscount(calcDiscount1(customer2.getCustomerClass()));
//        order3.setDiscount(calcDiscount1(customer3.getCustomerClass()));
//        order4.setDiscount(calcDiscount1(customer4.getCustomerClass()));

        order1.setDiscount(calcDiscount2(order1.getNum()));
        order2.setDiscount(calcDiscount2(order2.getNum()));
        order3.setDiscount(calcDiscount2(order3.getNum()));
        order4.setDiscount(calcDiscount2(order4.getNum()));

        System.out.println(order1.toString());
        System.out.println(order2.toString());
        System.out.println(order3.toString());
        System.out.println(order4.toString());

    }

    // 根据客户级别分别给予折扣
    // A类客户,打八折;B类客户,打九折;C类客户,打95折
    private static BigDecimal calcDiscount1(String customerClass){
        switch (customerClass){
            case "A":
                return BigDecimal.valueOf(0.8);
            case "B":
                return BigDecimal.valueOf(0.9);
            case "C":
                return BigDecimal.valueOf(0.95);
            default:
                return BigDecimal.valueOf(1);
        }
    }

    // 根据订单数量分别给予折扣
    // >=4000,打八折;>=3000 <4000,打九折;>=2000 <3000,打95折
    private static BigDecimal calcDiscount2(BigDecimal num){
        if (num.compareTo(BigDecimal.valueOf(4000))>=0) {
            return BigDecimal.valueOf(0.8);
        } else if (num.compareTo(BigDecimal.valueOf(3000))>=0) {
            return BigDecimal.valueOf(0.9);
        } else if (num.compareTo(BigDecimal.valueOf(2000))>=0) {
            return BigDecimal.valueOf(0.95);
        }
        return BigDecimal.valueOf(1);
    }
}

  • 从以上两段代码可以看到,公司的营销策略不是简单的根据同一种模式进行调整折扣系数,而是模式发生了实质性的变化:比如1季度需要按客户级别进行折扣,2季度又变换成了按订单量多少进行折扣,3季度又变成了按产品类别不同进行折扣…

2.2 采用设计模式

  • 这些营销策略的变换实际上就是折扣算法的变换,再想象一下采用策略模式应该怎么做:我们可以将这些算法独立出来并进行分别封装,形成算法族,在订单下达时根据当前启用的策略来调用不同的算法。
    在这里插入图片描述
  1. 定义一个营销策略的接口
/**
 * 营销策略接口
 *
 * @author zhuhuix
 * @date 2021-03-19
 */
public interface SalesStrategy {

    // 计算折扣
    BigDecimal calcDiscount(Order order);
}

  1. 通过继承接口分别实现不同的计算折扣的算法
/**
 * 营销策略1:根据客户级别计算折扣
 */
public class SalesStrategyByCustomerClass implements SalesStrategy {

    // 根据客户级别分别给予折扣
    // A类客户,打八折;B类客户,打九折;C类客户,打95折
    @Override
    public BigDecimal calcDiscount(Order order) {

        switch (order.getCustomer().getCustomerClass()) {
            case "A":
                return BigDecimal.valueOf(0.8);
            case "B":
                return BigDecimal.valueOf(0.9);
            case "C":
                return BigDecimal.valueOf(0.95);
            default:
                return BigDecimal.valueOf(1);
        }
    }
    
	 @Override
    public String toString() {
        return "SalesStrategyByCustomer";
    }

}

/**
 * 营销策略2:根据订单数量计算折扣
 */
public class SalesStrategyByOrderNum implements SalesStrategy {

    // 根据订单数量分别给予折扣
    // >=4000,打八折;>=3000 <4000,打九折;>=2000 <3000,打95折
    @Override
    public BigDecimal calcDiscount(Order order) {
        if (order.getNum().compareTo(BigDecimal.valueOf(4000))>=0) {
            return BigDecimal.valueOf(0.8);
        } else if (order.getNum().compareTo(BigDecimal.valueOf(3000))>=0) {
            return BigDecimal.valueOf(0.9);
        } else if (order.getNum().compareTo(BigDecimal.valueOf(2000))>=0) {
            return BigDecimal.valueOf(0.95);
        }
        return BigDecimal.valueOf(1);
    }
    
    @Override
    public String toString() {
        return "SalesStrategyByOrderNum";
    }
}
  1. 改写订单类,加入营销策略变量,及折扣计算
/**
 * 营销策略--订单
 *
 * @author zhuhuix
 * @date 2021-03-19
 */
public class Order {

    ...

    // 当前的营销策略
    private SalesStrategy salesStrategy;

	...

    public SalesStrategy getSalesStrategy() {
        return salesStrategy;
    }

	// 设置营销策略,并计算折扣
    public void setSalesStrategy(SalesStrategy salesStrategy) {
        this.salesStrategy = salesStrategy;
        setDiscount(this.salesStrategy.calcDiscount(this));
    }

    @Override
    public String toString() {
        return "Order{" +
                "customer=" + customer.getCustomerName() +
                ", product='" + product + '\'' +
                ", num=" + num +
                ", price=" + price +
                ", salesStrategy=" + salesStrategy.toString() +
                ", discount=" + discount +
                ", amount=" + amount +
                ", actualAmount=" + actualAmount +
                '}';
    }
}

  1. 最后改写主程序,满足可维护性,可扩展性原则
/**
 * 销售订单应用营销策略
 *
 * @author zhuhuix
 * @date 2021-03-19
 */
public class Sales {

    public static void main(String[] args) {

        // 创建客户
        Customer customer1 = new Customer("001","上海客户","A");
        Customer customer2 = new Customer("002","北京客户","B");
        Customer customer3 = new Customer("003","广州客户","C");
        Customer customer4 = new Customer("004","深圳客户","D");

        // 创建订单
        Order order1 = new Order(customer1,"产品", BigDecimal.valueOf(1000),BigDecimal.valueOf(10.5));
        Order order2 = new Order(customer2,"产品", BigDecimal.valueOf(2000),BigDecimal.valueOf(10.5));
        Order order3 = new Order(customer3,"产品", BigDecimal.valueOf(3000),BigDecimal.valueOf(10.5));
        Order order4 = new Order(customer4,"产品", BigDecimal.valueOf(4000),BigDecimal.valueOf(10.5));

        // 获取公司当前的营销策略
        SalesStrategy salesStrategy =getSalesStrategy();

        order1.setSalesStrategy(salesStrategy);
        order2.setSalesStrategy(salesStrategy);
        order3.setSalesStrategy(salesStrategy);
        order4.setSalesStrategy(salesStrategy);


        System.out.println(order1.toString());
        System.out.println(order2.toString());
        System.out.println(order3.toString());
        System.out.println(order4.toString());

    }

    // 模拟获取营销策略,实际项目中可以通过配置或数据库获取
    private static SalesStrategy getSalesStrategy(){
    	// 模拟
    	return new SalesStrategyByCustomerClass();
        // return  new SalesStrategyByOrderNum();
    } 
}
  • 分别模拟两种营销策略的执行
    在这里插入图片描述
    在这里插入图片描述

三、总结

  • 最后我们来总结一下策略模式的应用场景:
  1. 首先策略模式必须要有操作策略的上下文环境,在本例子中就是订单;
  2. 接着要抽象策略类(Strategy): 在本例中就是计算订单折扣这个接口;
  3. 最后要有具体的策略实现,在本例中就是各种订单折扣的算法实现。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智慧zhuhuix

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值