用最最最通俗易懂的例子来谈策略模式

本文通过具体案例解释了策略模式的概念及应用场景,包括订单折扣计算和文件解析等,展示了如何利用策略模式简化代码并遵循开闭原则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

策略模式是什么?

策略模式就是定义一个算法族,封装起来,算法族可以相互替换,根据需求,来选择相应的算法!

说的太官方了哦,都搞懵逼了,其实可以举一个男海王的例子,他有3个女朋友,第一个女朋友喜欢猛男,他就可以把自己打扮成猛男的样子;第二个女朋友喜欢奶一点,那他就把自己打扮成奶一点的样子;第三个女朋友该奶的时候奶,该狼的时候狼,他就可以兼顾!什么意思那,就是对于三个女朋友来说,男海王有三种不同的策略!这三种策略相当于一个算法族,并且可以相互替换!


为什么需要了解策略模式?

(看过我之前设计模式的朋友,肯定只要我要说啥了,来个传送门)使用策略模式,可以遵循设计原则(设计原则看这篇就够了),比如遵循开闭原则,每个策略相当于一个需求,需求是变的,使用策略模式,我们只需要添加新的需求就行了,不需要关注也业务的联系!在比如单一职责原则,每个策略相当于一个类,一个类只表示一种策略!


通过代码进一步理解策略模式

我们举一个客户下订单的例子,订单的价格会根据订单量或者客户类别来打折!

客户实体类

/**
 * @author: tianjx
 * @date: 2022/1/12 10:45
 * @description: 客户实体类
 */
public class Customer {
    /**
     * 客户编号
     */
    private String customerNo;
    /**
     * 客户名称
     */
    private String customerName;
    /**
     * 客户级别 A,B,C
     *
     */
    private String customerCalss;

    public Customer() {}

    public Customer(String customerNo, String customerName, String customerCalss) {
        this.customerNo = customerNo;
        this.customerName = customerName;
        this.customerCalss = customerCalss;
    }

    public String getCustomerNo() {
        return customerNo;
    }

    public void setCustomerNo(String customerNo) {
        this.customerNo = customerNo;
    }

    public String getCustomerName() {
        return customerName;
    }

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

    public String getCustomerCalss() {
        return customerCalss;
    }

    public void setCustomerCalss(String customerCalss) {
        this.customerCalss = customerCalss;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "customerNo='" + customerNo + '\'' +
                ", customerName='" + customerName + '\'' +
                ", customerCalss='" + customerCalss + '\'' +
                '}';
    }
}

订单实体类

/**
 * @author: tianjx
 * @date: 2022/1/12 10:56
 * @description: 订单类
 */
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() {
    }

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

    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;
    }

    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 +
                ", product='" + product + '\'' +
                ", num=" + num +
                ", price=" + price +
                ", discount=" + discount +
                ", amount=" + amount +
                ", actualAmount=" + actualAmount +
                '}';
    }
}

未使用策略模式

/**
 * @author: tianjx
 * @date: 2022/1/12 10:24
 * @description: 行为型模式-策略模式
 * 例子:客户下订单,通过不同的营销策略来打不同的折扣
 */

public class StragegyModeDemo {
    public static void main(String[] args) {
        Customer customerA = new Customer("1","A级别用户","A");
        Customer customerB = new Customer("2","B级别用户","B");
        Customer customerC = new Customer("3","C级别用户","C");

        Order orderA = new Order(customerA,"鼠标", BigDecimal.valueOf(5),BigDecimal.valueOf(99));
        Order orderB = new Order(customerB,"键盘", BigDecimal.valueOf(15),BigDecimal.valueOf(199));
        Order orderC = new Order(customerC,"显示器", BigDecimal.valueOf(21),BigDecimal.valueOf(999));

//        orderA.setDiscount(calcDiscount01(orderA.getCustomer().getCustomerCalss()));
//        orderB.setDiscount(calcDiscount01(orderB.getCustomer().getCustomerCalss()));
//        orderC.setDiscount(calcDiscount01(orderC.getCustomer().getCustomerCalss()));
        orderA.setDiscount(calcDiscount02(orderA.getNum()));
        orderB.setDiscount(calcDiscount02(orderB.getNum()));
        orderC.setDiscount(calcDiscount02(orderC.getNum()));

        orderA.setAmount(calcMultiply(orderA.getNum(),orderA.getPrice()));
        orderB.setAmount(calcMultiply(orderB.getNum(),orderB.getPrice()));
        orderC.setAmount(calcMultiply(orderC.getNum(),orderC.getPrice()));

        orderA.setActualAmount(calcMultiply(orderA.getDiscount(),orderA.getAmount()));
        orderB.setActualAmount(calcMultiply(orderB.getDiscount(),orderB.getAmount()));
        orderC.setActualAmount(calcMultiply(orderC.getDiscount(),orderC.getAmount()));

        System.out.println(orderA.toString());
        System.out.println(orderB.toString());
        System.out.println(orderC.toString());
    }

    // 计算折扣 根据用户级别来算折扣
    private static BigDecimal calcDiscount01(String customerClass){
        switch (customerClass){
            case "A":
                return BigDecimal.valueOf(0.9);
            case "B":
                return BigDecimal.valueOf(0.8);
            case "C":
                return BigDecimal.valueOf(0.75);
        }
        return BigDecimal.valueOf(0);
    }

    // 计算折扣 根据订单量来算折扣
    private static BigDecimal calcDiscount02(BigDecimal num){
        if (num.compareTo(BigDecimal.valueOf(10)) == -1) {
            return BigDecimal.valueOf(0.9);
        } else if (num.compareTo(BigDecimal.valueOf(20)) == -1) {
            return BigDecimal.valueOf(0.8);
        } else {
            return BigDecimal.valueOf(0.75);
        }
    }

    // 计算总原价
    private static BigDecimal calcMultiply(BigDecimal one,BigDecimal two){
        return one.abs().multiply(two.abs());
    }
}

使用策略模式

定义策略模式接口

/**
 * @author: tianjx
 * @date: 2022/1/12 18:03
 * @description: 策略模式接口
 */
public interface SalesStrategy {
    BigDecimal calcDiscount(Order order);
}

定义策略模式实现类

/**
 * @author: tianjx
 * @date: 2022/1/12 18:04
 * @description: 根据客户类别打折
 */
public class SalesStrategyByCustomerClass implements SalesStrategy{

    @Override
    public BigDecimal calcDiscount(Order order) {
        switch (order.getCustomer().getCustomerCalss()){
            case "A":
                return BigDecimal.valueOf(0.9);
            case "B":
                return BigDecimal.valueOf(0.8);
            case "C":
                return BigDecimal.valueOf(0.75);
        }
        return BigDecimal.valueOf(0);
    }

    @Override
    public String toString() {
        return "SalesStrategyByCustomerClass{}";
    }
}


/**
 * @author: tianjx
 * @date: 2022/1/12 18:06
 * @description: 根据订单量来打折
 */
public class SalesStrategyByOrderNum implements SalesStrategy{

    @Override
    public BigDecimal calcDiscount(Order order) {
        if (order.getNum().compareTo(BigDecimal.valueOf(10)) == -1) {
            return BigDecimal.valueOf(0.9);
        } else if (order.getNum().compareTo(BigDecimal.valueOf(20)) == -1) {
            return BigDecimal.valueOf(0.8);
        } else {
            return BigDecimal.valueOf(0.75);
        }
    }

    @Override
    public String toString() {
        return "SalesStrategyByOrderNum{}";
    }
}

订单实体类添加策略模式

/**
 * @author: tianjx
 * @date: 2022/1/12 10:56
 * @description: 订单类
 */
public class Order {
    
    ......

    // 营销策略
    private SalesStrategy salesStrategy;

    public SalesStrategy getSalesStrategy() {
        return salesStrategy;
    }

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

测试调用

/**
 * @author: tianjx
 * @date: 2022/1/12 18:08
 * @description:
 */
public class StragegyModeDemo02 {
    public static void main(String[] args) {
        Customer customerA = new Customer("1","A级别用户","A");
        Customer customerB = new Customer("2","B级别用户","B");
        Customer customerC = new Customer("3","C级别用户","C");

        Order orderA = new Order(customerA,"鼠标", BigDecimal.valueOf(5),BigDecimal.valueOf(99));
        Order orderB = new Order(customerB,"键盘", BigDecimal.valueOf(15),BigDecimal.valueOf(199));
        Order orderC = new Order(customerC,"显示器", BigDecimal.valueOf(21),BigDecimal.valueOf(999));


        orderA.setSalesStrategy(new SalesStrategyByCustomerClass());
        orderB.setSalesStrategy(new SalesStrategyByOrderNum());
        orderC.setSalesStrategy(new SalesStrategyByOrderNum());

        orderA.setAmount(calcMultiply(orderA.getNum(),orderA.getPrice()));
        orderB.setAmount(calcMultiply(orderB.getNum(),orderB.getPrice()));
        orderC.setAmount(calcMultiply(orderC.getNum(),orderC.getPrice()));

        orderA.setActualAmount(calcMultiply(orderA.getDiscount(),orderA.getAmount()));
        orderB.setActualAmount(calcMultiply(orderB.getDiscount(),orderB.getAmount()));
        orderC.setActualAmount(calcMultiply(orderC.getDiscount(),orderC.getAmount()));

        System.out.println(orderA.toString());
        System.out.println(orderB.toString());
        System.out.println(orderC.toString());
    }


    // 计算总原价
    private static BigDecimal calcMultiply(BigDecimal one,BigDecimal two){
        return one.abs().multiply(two.abs());
    }
}

可以看出,如果没有使用策略的话,当有新的营销策略的时候,还得再写方法,修改原来的代码,如果使用了策略模式,我们只需要在定一个新的类就可以了,改一下策略模式就行了!首先非常符合开闭原则,而且更加不会让我们的代码显的臃肿!


在来一个例子,在换一种写法,在加深一下印象!(在我这必须让大家理解明明白白的)

分析:目的是解析文件,但是文件有word,excel两种,那我们就定义一个策略接口,两种实现方式即可!

定义一个枚举

/**
 * @author: tianjx
 * @date: 2022/1/13 10:48
 * @description:
 */
public enum FileTypeResolveType {
    FILE_WORD_RESOLVE("FILE_WORD_RESOLVE","WORD文件类型"),
    FILE_EXCEL_RESOLVE("FILE_EXCEL_RESOLVE","EXCLE文件类型"),
    FILE_DEFAULT_RESOLVE("FILE_DEFAULT_RESOLVE","默认文件类型");

    FileTypeResolveType(String type, String content) {}
}

定义策略接口

/**
 * @author: tianjx
 * @date: 2022/1/13 10:52
 * @description: 文件解析接口
 */
public interface IFileStrategy {
    // 文件解析类型
    FileTypeResolveType gainFileType();
    // 子类实现的具体解析方式
    void resolve(Object params);
}

定义策略实现类

/**
 * @author: tianjx
 * @date: 2022/1/13 10:55
 * @description:
 */
@Component
public class ExcelFileResolve implements IFileStrategy{
    @Override
    public FileTypeResolveType gainFileType() {
        return FileTypeResolveType.FILE_EXCEL_RESOLVE;
    }

    @Override
    public void resolve(Object params) {
        System.out.println("解析EXCEL文件!!!");
    }
}

/**
 * @author: tianjx
 * @date: 2022/1/13 10:53
 * @description:
 */
@Component
public class WordFileResolve implements IFileStrategy{
    @Override
    public FileTypeResolveType gainFileType() {
        return FileTypeResolveType.FILE_WORD_RESOLVE;
    }

    @Override
    public void resolve(Object params) {
        System.out.println("解析word文件!!");
    }
}


/**
 * @author: tianjx
 * @date: 2022/1/13 10:56
 * @description:
 */
@Component
public class DefaultFileResolve implements IFileStrategy{

    @Override
    public FileTypeResolveType gainFileType() {
        return FileTypeResolveType.FILE_DEFAULT_RESOLVE;
    }

    @Override
    public void resolve(Object params) {
        System.out.println("默认文件解析类型!!!");
    }
}

与spring整合,继承ApplicationContextAware

@Component
public class StragetyUserService implements ApplicationContextAware {

    private Map<FileTypeResolveType,IFileStrategy> iFileStrategyMap = new ConcurrentHashMap<>();

    // 对外提供的方法,调用就行
    public void resolveFile(FileTypeResolveType fileTypeResolveType,Object params){
        IFileStrategy iFileStrategy = iFileStrategyMap.get(fileTypeResolveType);
        if (iFileStrategy != null){
            iFileStrategy.resolve(params);
        }
    }


    // 把所有的策略放到 iFileStrategyMap 中
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, IFileStrategy> tmepMap = applicationContext.getBeansOfType(IFileStrategy.class);
        tmepMap.values().forEach(strategyService -> {
            iFileStrategyMap.put(strategyService.gainFileType(), strategyService);
        });
    }
}

测试

@SpringBootTest
class DemoApplicationTests {

    @Autowired
    StragetyUserService stragetyUserService;

    @Test
    void contextLoads() {
        stragetyUserService.resolveFile(FileTypeResolveType.FILE_WORD_RESOLVE, "asd");
        stragetyUserService.resolveFile(FileTypeResolveType.FILE_EXCEL_RESOLVE, "asd");
        stragetyUserService.resolveFile(FileTypeResolveType.FILE_DEFAULT_RESOLVE, "asd");
    }

}

在这里插入图片描述

有没有感受到代码的优雅,首先不同策略有不同的实现方式,符合单一职责!其次如果添加新的策略,只需添加相应的实现类即可!非常的方便,所以我们的代码还是非常的优雅的!


来个小总结呗~

策略模式就是相同的功能上,有不同的策略!一般适用于if...elseif...else的场景!

不过可能也有人认为每次都添加一个类很麻烦,这个就是适当应用,其实根据上面的两个例子来讲,策略模式也只是一种让代码优雅的思想,让我们再写代码的时候多了一种方式方法!选不选用还是看具体情况!



感谢大家的阅读,我是Alson_Code🆒,一个喜欢把简单问题复杂化,把复杂问题简单化的程序猿!

感谢:参考博客一参考博客二

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值