每一年都奔走在自己热爱里 没有人是一座孤岛,总有谁爱着你

岁
万
月
12

策略模式

项目地址:https://gitee.com/libeimaningg/beizhilib

(一)简介

设计模式简介
将设计者的思维融入大家的学习和工作中,更高层次的思考!
• 创建型模式:
– 单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式。

• 结构型模式:
– 适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。

• 行为型模式:
– 模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。

本次文章介绍的是策略模式。

1、什么是策略模式?

策略设计模式是一种行为型设计模式,它允许在运行时根据不同的情况选择算法或策略。
这种模式提供了一种灵活的方法来改变算法或策略,而无需修改代码。


这个模式主要由三个角色组成:Context(上下文)、Strategy(策略)和 ConcreteStrategy(具体策略)。

  • Context(上下文):它是包含了一个Strategy接口的引用,用来调用具体策略的方法。上下文可以根据需要改变策略。
  • Strategy(策略):它是一个接口,定义了一个算法族,这些算法可以相互替换。具体策略可以实现这个接口,这样就可以提供不同的实现方式。
  • ConcreteStrategy(具体策略):它是具体的策略实现,实现了策略接口中定义的方法。每个具体策略都实现了一种算法。
    image
    策略模式最大的作用在于分离使用算法的逻辑和算法自身实现的逻辑,这样就意味着当我们想要优化算法自身的实现逻辑时就变得非常便捷,一方面可以采用最新的算法实现逻辑,另一方面可以直接弃用旧算法而采用新算法。使用策略模式能够很方便地进行替换。

2、策略模式的优缺点

  • 优点:
    (1)算法策略可以自由实现切换
    (2)扩展性好,加一个策略,只需要增加一个类
    (3)避免使用多重条件选择语句(if else),充分体现面向对象设计思想。
    (4)复用性:策略类可以在不同上下文中复用。
    (5)符合单一职责原则:每个策略类仅关注一个算法。
  • 缺点:
    (1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
    (2)类数量增加:每个策略需要一个独立类,可能导致类膨胀。

3、策略模式的应用场景

  • 接收外部系统的报文时,根据报文类型去选择对应的报文处理逻辑
  • 支付方式选择:在电商平台中,用户可以选择多种支付方式,如支付宝、微信支付、银行卡支付等。这些支付方式可以看作是策略,用户选择不同的支付方式就是选择了不同的策略。
  • 排序算法:在Java中,有多种排序算法可以选择,如快速排序、归并排序、冒泡排序等。这些排序算法也可以看作是策略,根据不同的需求选择不同的排序算法就是选择了不同的策略。
  • 表单验证:在Web开发中,通常需要对用户输入的表单数据进行验证。不同的表单数据验证方式可以看作是策略,根据表单的不同需求选择不同的验证策略。
  • 税收计算:在财务软件中,根据不同的国家和地区的税收政策,需要对税收计算方式进行不同的选择,这些税收计算方式也可以看作是策略。

(二)具体用法

第一种写法

1、定义策略接口

package org.yaoyao.yaoyaobiz.service.strategy;

/**
 * 处理策略接口
 *
 * @author Bryson
 * @date 2025/3/25
 */
public interface Strategy {
    void handleCallBack();
}

2、定义策略上下文,处理策略工厂服务类

package org.yaoyao.yaoyaobiz.service.strategy.factory;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.yaoyao.yaoyaobiz.service.strategy.Strategy;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 处理策略工厂服务类
 *
 * @author Bryson
 * @date 2025/3/25
 */
public class StrategyFactory {

    //策略服务类集合
    public static Map<String, Strategy> strategyMap = new ConcurrentHashMap<>();

    //根据不同的策略获取对应的策略服务类
    public static Strategy getInvokeStrategy(String strategy) {
        return strategyMap.get(strategy);
    }

    //注册策略服务类
    public static void register(String strategy, Strategy strategyService) {
        if (StringUtils.isBlank(strategy) || null == strategyService) {
            return;
        }
        strategyMap.put(strategy, strategyService);
    }

}

3、定义具体实现类

(1)具体实现策略一:

@Service
public class strategyOne implements Strategy, InitializingBean {
    private static final Logger log = LoggerFactory.getLogger(strategyOne.class);

    @Override
    public void handleCallBack() {
        log.info("策略一,1,男");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        //添加到策略工厂
        StrategyFactory.register(BusinessContants.BUSINESS_CODE_M, this);
    }
}

(2)具体实现策略二:

@Service
public class strategyTwo implements Strategy , InitializingBean {
    private static final Logger log = LoggerFactory.getLogger(strategyTwo.class);

    @Override
    public void handleCallBack() {
        log.info("策略二,0,女");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        //添加到策略工厂
        StrategyFactory.register(BusinessContants.BUSINESS_CODE_F, this);
    }
}

4、使用策略

@Override
    public void strategyTest(UserDto userDto) {
        if (StringUtils.isNotEmpty(userDto.getSex())) {
            //根据性别查找对应的策略
            Strategy invokeStrategy = StrategyFactory.getInvokeStrategy(userDto.getSex());
            if (invokeStrategy != null) {
                invokeStrategy.handleCallBack();
            }
        }
    }

第二种写法

1、定义策略接口

public interface Strategy2 {
    void handleCallBack2();
}

2、定义操作功能枚举

package org.yaoyao.yaoyaobiz.enums;

import org.yaoyao.yaoyaobiz.service.impl.strategy.strategyOne;
import org.yaoyao.yaoyaobiz.service.impl.strategy.strategyTwo;
import org.yaoyao.yaoyaobiz.service.strategy.Strategy2;
import org.yaoyao.yaoyaocommon.utils.ContextUtil;

import java.util.Arrays;

/**
 * 操作功能枚举
 *
 * @author Bryson
 * @date 2025/3/26
 */
public enum Strategy2FuncCdEnums {

    FUNCTION_ONE("0", "操作功能一", ContextUtil.getBean(strategyTwo.class)),
    FUNCTION_TWO("1", "操作功能二", ContextUtil.getBean(strategyOne.class));

    /**
     * 编码
     */
    private String code;

    /**
     * 名称
     */
    private String name;

    private Strategy2 strategy2;

    Strategy2FuncCdEnums(String code, String name, Strategy2 strategy2) {
        this.code = code;
        this.name = name;
        this.strategy2 = strategy2;
    }

    public String getCode() {
        return code;
    }

    public String getName() {
        return name;
    }

    public Strategy2 getStrategy2() {
        return strategy2;
    }

    public static Strategy2FuncCdEnums getStrategy2FuncCdEnums(String code) {
        return Arrays.stream(Strategy2FuncCdEnums.values()).filter(x -> x.getCode().equalsIgnoreCase(code)).findFirst().orElse(null);
    }

}

3、定义具体实现类

具体实现类一:

@Service
public class strategyOne implements Strategy2 {
    private static final Logger log = LoggerFactory.getLogger(strategyOne.class);

    @Override
    public void handleCallBack2() {
        log.info("策略一,1,男");
    }
}

具体实现类二:

@Service
public class strategyTwo implements Strategy2 {
    private static final Logger log = LoggerFactory.getLogger(strategyTwo.class);

    @Override
    public void handleCallBack2() {
        log.info("策略二,0,女");
    }
}

4、使用策略

@Override
    public void strategy2Test(UserDto userDto) {
        String funcCd = userDto.getSex();
        Strategy2FuncCdEnums funcCdEnum = Strategy2FuncCdEnums.getStrategy2FuncCdEnums(funcCd);
        if (ObjectUtil.isEmpty(funcCdEnum)) {
            throw new BusinessException(StatusEnums.FAIL, BusinessEnums.FAIL.getType(), "未知的操作功能");
        }
        //根据性别查找对应的策略
        funcCdEnum.getStrategy2().handleCallBack2();
    }
posted @ 2025-03-25 17:15  果咩那塞  阅读(9)  评论(0)    收藏  举报