设计模式之策略模式

一、介绍

所谓策略模式,指的是做某一件事时有多种选择(即策略),且不同的策略之间相互独立,而且无论使用哪种策略,得到的结果都是相同的

二、角色定义

Context封装角色

这个角色是策略模式中的重要组成部分,通常用于存储和传递策略对象,以及处理策略对象的交互逻辑。上下文对象在客户端的请求下,会调用合适的策略对象来执行相应的操作。

Strategy抽象策略角色

这个角色通常是一个接口,用于定义各种策略对象的共同方法。具体策略对象实现这个接口,并包含具体的算法实现。策略对象不持有任何上下文对象的状态,这样保证了策略对象的可复用性。

ConcreteStrategy具体策略角色

这个角色是实现策略接口的具体类,包含了具体的算法实现。具体策略对象通常会持有上下文对象的状态,以便在执行算法时能够访问和修改这些状态。

三、案例

定义抽象的策略接口

java 复制代码
/**
 * 支付策略接口
 */
public interface PayStrategy {
    /**
     * 实际支付金额计算
     * @param money
     */
    Double compute(Double money);
}

定义具体的支付策略类

java 复制代码
/**
 * 非会员计费策略
 */
public class Level0Strategy implements PayStrategy{
    @Override
    public Double compute(Double money) {
        System.out.println("非会员开始计费");
        return money;
    }
}
java 复制代码
/**
 * 初级会员计费策略
 */
public class Level1Strategy implements PayStrategy{
    @Override
    public Double compute(Double money) {
        System.out.println("初级会员开始计费");
        return money*0.8;
    }
}
java 复制代码
/**
 * 中级会员计费策略
 */
public class Level2Strategy implements PayStrategy{
    @Override
    public Double compute(Double money) {
        System.out.println("中级会员开始计费");
        return money*0.7;
    }
}
java 复制代码
/**
 * 高级会员计费策略
 */
public class Level3Strategy implements PayStrategy{
    @Override
    public Double compute(Double money) {
        System.out.println("高级会员开始计费");
        return money*0.5;
    }
}

定义用于存储和传递策略的上下文

java 复制代码
/**
 * 支付策略上下文
 */
public class StrategyContent {
    private PayStrategy payStrategy;

    public StrategyContent(PayStrategy payStrategy) {
        this.payStrategy = payStrategy;
    }

    /**
     * 支付方法
     * @param money
     * @return
     */
    public Double pay(Double money){
        return this.payStrategy.compute(money);
    }
}

定义策略工厂类,用于生产具体的策略

java 复制代码
/**
 * 策略工厂
 */
public class PayStrategyFactory {

    public static PayStrategy getStrategy(Member member){
        PayStrategy payStrategy;
        switch (member.getLevel()){
            case "初级":
                payStrategy=new Level1Strategy();
                break;
            case "中级":
                payStrategy=new Level2Strategy();
                break;
            case "高级":
                payStrategy=new Level3Strategy();
                break;
            default:
                payStrategy=new Level0Strategy();
                break;
        }
        return payStrategy;
    }
}

编写客户端

java 复制代码
@Data
@AllArgsConstructor
public class Member {
    /**
     * 会员姓名
     */
    private String name;
    /**
     * 会员等级:非会员、初级、中级、高级
     */
    private String level;
    /**
     * 支付金额
     */
    private Double pay;
}

测试

java 复制代码
public class Test {
    public static void main(String[] args) {
        Member member = new Member("小明", "初级", 100.00);
        PayStrategy strategy = PayStrategyFactory.getStrategy(member);
        StrategyContent strategyContent = new StrategyContent(strategy);
        Double pay = strategyContent.pay(member.getPay());
        System.out.println(member.getName() + "应支付金额:" + member.getPay() + ",实际支付金额:" + pay);
        member = new Member("小红", "中级", 100.00);
        strategy = PayStrategyFactory.getStrategy(member);
        strategyContent = new StrategyContent(strategy);
        pay = strategyContent.pay(member.getPay());
        System.out.println(member.getName() + "应支付金额:" + member.getPay() + ",实际支付金额:" + pay);
        member = new Member("铁蛋", "高级", 100.00);
        strategy = PayStrategyFactory.getStrategy(member);
        strategyContent = new StrategyContent(strategy);
        pay = strategyContent.pay(member.getPay());
        System.out.println(member.getName() + "应支付金额:" + member.getPay() + ",实际支付金额:" + pay);
        member = new Member("李刚", "非会员", 100.00);
        strategy = PayStrategyFactory.getStrategy(member);
        strategyContent = new StrategyContent(strategy);
        pay = strategyContent.pay(member.getPay());
        System.out.println(member.getName() + "应支付金额:" + member.getPay() + ",实际支付金额:" + pay);
    }
}

四、适用场景

  • 不同业务逻辑:在同一个业务逻辑中,可能会存在不同的策略或算法。例如,在电商网站中,可以根据不同的促销策略对商品进行不同的定价。在这种情况下,可以使用策略模式来封装不同的促销策略,并在运行时根据需要选择合适的策略。

  • 数据排序策略:在处理大量数据时,可能需要使用不同的排序算法。例如,冒泡排序、选择排序、插入排序和二叉树排序等。在这种情况下,可以使用策略模式来定义不同的排序策略,并在运行时根据需要选择合适的策略。

  • 算法切换:在某些情况下,可能需要根据不同的条件切换不同的算法。例如,在进行实时计算时,可能需要根据不同的输入数据选择不同的计算算法。在这种情况下,可以使用策略模式来封装不同的算法,并在运行时根据需要选择合适的算法。

  • 行为切换:在系统中,可能需要根据不同的条件切换不同的行为。例如,在一个游戏中,可能需要根据不同的关卡选择不同的游戏策略。在这种情况下,可以使用策略模式来封装不同的游戏策略,并在运行时选择合适的行为

五、优缺点

优点

  • 避免使用多重条件语句:策略模式通过使用策略类和上下文对象来避免使用多重条件语句,如if-else语句或switch-case语句。通过将算法的行为封装到策略类中,并在运行时根据客户端的需求选择相应的算法,策略模式使得代码更加简洁、易于维护和扩展。

  • 提供可重用的算法族:策略模式通过定义抽象策略类和具体策略类,提供了一系列的算法实现。这些算法可以在不同的上下文中重复使用,通过组合和替换不同的策略对象来满足客户端的需求。

  • 分离算法和客户端:策略模式将算法的实现和使用分离到具体的策略类和上下文对象中。客户端只需要与上下文对象进行交互,而不需要直接处理算法的实现细节。这种分离使得代码更加清晰、易于理解和维护。

  • 支持对开闭原则的完美支持:策略模式可以在不修改原有代码的情况下,灵活地增加新的算法。通过定义新的策略类和上下文对象,可以轻松地将新的算法集成到现有系统中,满足新的需求。

  • 将算法的使用放到环境类中:策略模式将算法的使用放到上下文对象中,而算法的实现则移到具体策略类中。这种分离使得代码更加清晰、易于管理和扩展。

  • 客户端必须理解所有策略算法的区别:策略模式要求客户端必须理解所有可用的策略算法的区别,以便在适当的时候选择合适的算法。这可能增加了客户端的复杂性和学习成本。

缺点

  • 可能导致过多的策略类:策略模式可能导致创建过多的策略类,每个算法都对应一个策略类。这可能会增加系统的复杂性和维护成本

六、总结

总之,策略模式是一种行为型设计模式,它通过封装一系列可重用的算法实现,并将它们组合到不同的上下文中,实现了算法的行为和使用的分离。这种模式使得代码更加灵活、易于维护和扩展,同时支持在不修改原有代码的情况下增加新算法,从而提高了代码的灵活性和可维护性

相关推荐
佛祖让我来巡山4 小时前
【面试题】什么是观察者模式?一般用在什么场景?
观察者模式·设计模式
Yu_Lijing4 小时前
基于C++的《Head First设计模式》笔记——适配器模式
c++·笔记·设计模式
点云SLAM4 小时前
C++ 设计模式之工厂模式(Factory)和面试问题
开发语言·c++·设计模式·面试·c++11·工厂模式
红头辣椒4 小时前
AI赋能全流程,重塑需求管理新生态——Visual RM需求数智化平台核心能力解析
人工智能·设计模式·软件工程·需求分析·用户运营
魅影骑士001019 小时前
柯里化函数
后端·设计模式
BHXDML1 天前
Java 设计模式详解
java·开发语言·设计模式
Engineer邓祥浩1 天前
设计模式学习(12) 23-10 外观模式
学习·设计模式·外观模式
Geoking.1 天前
【设计模式】享元模式(Flyweight)详解:用共享对象对抗内存爆炸
java·设计模式·享元模式
callJJ1 天前
Spring设计模式与依赖注入详解
java·spring·设计模式·idea·工厂模式