设计模式-策略模式

设计模式-策略模式

策略模式,英文全称是 Strategy Design Pattern。它是这样定义的:Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. 翻译成中文就是:定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指使用算法的代码)。

策略模式解耦了策略的定义、创建、使用这三部分。

案例分析

我之前做过一个审核系统,需要审核很多东西,例如注册资本超过100w得2分,否则不得分,用房面积每20平得0.2分等等

通过一些系统设计,审核操作需要传递的参数定义如下:

java 复制代码
@Data
public class Input {

    private String type;

    private Map<String, String> data;

}

type 字段标识当前审核的是哪一个类型的数据(注册资本、用房面积等),data 存储的是审核的值,这里省略了一些细节,例如审核状态、这条记录在审核表对应的审核ID等等

定义策略和对应的实现类

java 复制代码
// 策略接口
public interface Strategy {

    BigDecimal compute(Input input);

}

// 用房面积策略类
public class AccommodationStrategy implements Strategy {

    @Override
    public BigDecimal compute(Input input) {
        Map<String, String> inputData = input.getData();
        String coveredArea = inputData.get("coveredArea");
        if (coveredArea != null) {
            BigDecimal capitalValue = new BigDecimal(coveredArea);
            return capitalValue.divideToIntegralValue(new BigDecimal("20"))
                    .multiply(new BigDecimal("0.2"));
        }
        throw new IllegalArgumentException("coveredArea is required");
    }

}

// 注册资本策略类
public class RegisteredCapitalStrategy implements Strategy {

    @Override
    public BigDecimal compute(Input input) {
        Map<String, String> inputData = input.getData();
        String capital = inputData.get("Registered capital");
        if (capital != null) {
            BigDecimal capitalValue = new BigDecimal(capital);
            if (capitalValue.compareTo(new BigDecimal("100")) >= 0) {
                return new BigDecimal("2");
            }
            return new BigDecimal("0");
        }
        throw new IllegalArgumentException("Registered capital is required");
    }

}

在使用的时候,可以利用 switch case 或 if else 判断选择对应的策略类,由于它们实现了相同的接口因此可以互相替换

java 复制代码
public class Main {

    public static void main(String[] args) {
        Input input = new Input();
        input.setData(Map.of("coveredArea", "100"));
        input.setType("accommodation");
        test(input);
    }

    private static void test(Input input) {
        if (input.getData() == null) {
            throw new IllegalArgumentException("invalid data");
        }
        Strategy strategy = null;
        String type = input.getType();
        if ("accommodation".equals(type)) {
            strategy = new AccommodationStrategy();
        } else if ("registeredCapital".equals(type)) {
            strategy = new RegisteredCapitalStrategy();
        }
        if (strategy == null) {
            throw new IllegalArgumentException("invalid type");
        }
        System.out.println(strategy.compute(input));  
    }
    
}

但是这样的 if 判断在多的时候会非常繁琐,而且策略的算分逻辑是一直不变的,没有必要每次都重新 new 一个对象出来,可以借助之前的工厂模式简化 if else 判断以及每次返回同一个对象

java 复制代码
public interface Constants {

    Map<String, Strategy> STRATEGY_MAP = Map.of(
            "accommodation", new AccommodationStrategy(),
            "registeredCapital", new RegisteredCapitalStrategy()
    );

}
java 复制代码
public class Main {

    public static void main(String[] args) {
        Input input = new Input();
        input.setData(Map.of("coveredArea", "100"));
        input.setType("accommodation");
        test(input);
    }

    private static void test(Input input) {
        if (input.getData() == null) {
            throw new IllegalArgumentException("invalid data");
        }
        String type = input.getType();
        Strategy strategy = Constants.STRATEGY_MAP.get(type);
        if (strategy == null) {
            throw new IllegalArgumentException("invalid type");
        }
        System.out.println(strategy.compute(input));
    }

}

"运行时动态确定"是策略模式最典型的应用场景,根据配置文件或参数动态选择策略类,不过按照上述的代码(静态 Map 存储对应策略关系),每次返回的都是之前的对象,不能做到每次返回新的对象,有没有什么办法呢?

我们可以不存储真正的策略类实例对象,而是存储类路径,每次通过反射创建,这样每次拿到的就都是全新的对象了。

相关推荐
饼干哥哥10 小时前
Openclaw已死?任何Agent都能用Cli实现AI自主运营跨境电商
设计模式·openai·ai编程
折哥的程序人生 · 物流技术专研11 小时前
第4篇:抽象工厂模式——产品族一键创建
java·设计模式·抽象工厂模式·创建型模式·编程进阶·产品族·扩充系列
端庄的战斗机1 天前
javascript 设计模式(文章很长,请自备瓜子,水果和眼药水)
开发语言·javascript·设计模式
大侠锅锅1 天前
第 4 篇:策略模式实践——用统一接口管理 Docker 容器、原生进程与 K3s Pod
docker·容器·边缘计算·策略模式·iot
饼干哥哥1 天前
我开发了一个「吃掉」别人Skill来升级的饕餮.Skill,现在免费开源
人工智能·设计模式·开源
CaffeinePro1 天前
什么是系统架构?架构师到底在做什么?
设计模式·架构
AI人工智能+电脑小能手1 天前
【大白话说Java面试题 第156题】【06_Spring篇】第16题:Spring 用到了哪些设计模式?
java·spring·设计模式·代理模式·工厂模式
前端百草阁2 天前
JavaScript 设计模式(23 种)
开发语言·前端·javascript·设计模式
geovindu2 天前
java: Singleton Pattern
java·开发语言·后端·单例模式·设计模式·创建型模式
geovindu2 天前
python: Functional Options Pattern
开发语言·后端·python·设计模式·惯用法模式·函数式选项模式