策略模式 + 工厂模式

发布于:2025-09-04 ⋅ 阅读:(14) ⋅ 点赞:(0)

策略模式:

简单来说解决的行为的封装与选择。如HandlerMapping,将 HTTP 请求映射到对应的处理器(Controller 或方法)。

工厂模式:

解决的是具有相同属性的对象创建问题,如BeanFactory创建bean对象。

解决的代码问题:

// 1. 定义具体支付类,但没有统一的接口
public class Alipay {
    public void pay(double amount) {
        System.out.println("使用支付宝支付:" + amount + "元");
        // 调用支付宝SDK的具体逻辑
    }
}

public class WechatPay {
    public void executePayment(double amount) { // 方法名都不统一
        System.out.println("使用微信支付:" + amount + "元");
        // 调用微信支付SDK的具体逻辑
    }
}

// 2. 客户端代码直接创建具体对象并调用
public class PaymentService {
    public void processPayment(String paymentType, double amount) {
        if ("alipay".equalsIgnoreCase(paymentType)) {
            Alipay alipay = new Alipay(); // 直接依赖具体类Alipay
            alipay.pay(amount);
        } else if ("wechat".equalsIgnoreCase(paymentType)) {
            WechatPay wechatPay = new WechatPay(); // 直接依赖具体类WechatPay
            wechatPay.executePayment(amount); // 方法名不统一,增加使用难度
        } else {
            throw new IllegalArgumentException("不支持的支付方式");
        }
        // 如果日后要为Alipay的创建增加缓存、初始化等复杂逻辑,这里会变得臃肿
    }
}

// 3. 另一个服务也可能需要创建支付对象,导致代码重复
public class OrderService {
    public void createOrder(String paymentType) {
        // ... 订单创建逻辑
        // 又一套if-else来判断支付类型并创建对象
        if ("alipay".equalsIgnoreCase(paymentType)) {
            Alipay alipay = new Alipay(); // 创建逻辑重复
            // ... 可能还有其他操作
        } else if ("wechat".equalsIgnoreCase(paymentType)) {
            WechatPay wechatPay = new WechatPay();
            // ...
        }
    }
}

问题:

  • 高耦合(Tight Coupling)​​:PaymentServiceOrderService等客户端代码直接依赖具体的支付类(Alipay, WechatPay)。一旦这些具体类发生变化(如构造函数改变),所有创建它们的地方都需要修改

  • 违反开闭原则(Violates Open/Closed Principle)​​:当需要增加一个新的支付方式(如UnionPay银联支付)时,​必须修改所有包含支付类型判断 if-else分支的客户端代码(如 PaymentService, OrderService)。这使得系统难以扩展,也容易在修改时引入错误

  • 代码重复(Code Duplication)​​:对象的创建逻辑分散在应用程序的多个地方。如果创建过程很复杂(例如需要配置密钥、初始化连接等),这些重复的代码会难以维护

  • 可读性和可维护性差(Poor Readability and Maintainability)​​:客户端代码中充斥着具体的实例化操作和类型判断,​掩盖了核心的业务逻辑,使得代码难以理解和维护

  • 难以测试(Hard to Test)​​:由于客户端直接实例化具体对象,在进行单元测试时,很难模拟(Mock)​​ 这些依赖,从而难以隔离测试目标单元

策略模式解决的代码问题:

// ❌ 未使用策略模式的支付处理函数 - 圈复杂度高,难以维护
public class PaymentService {
    
    public void processPayment(String paymentType, double amount) {
        if ("alipay".equalsIgnoreCase(paymentType)) {
            System.out.println("调用支付宝SDK,支付¥" + amount);
            // 实际的支付宝支付逻辑,可能很复杂,包括参数组装、加密、调用网关等
        } else if ("wechat".equalsIgnoreCase(paymentType)) {
            System.out.println("调用微信支付SDK,支付¥" + amount);
            // 实际的微信支付逻辑
        } else if ("creditCard".equalsIgnoreCase(paymentType)) {
            System.out.println("调用银联接口,支付¥" + amount);
            // 实际的信用卡支付逻辑,可能包括卡号验证、有效期检查、3D认证等
        } else if ("applePay".equalsIgnoreCase(paymentType)) {
            System.out.println("调用Apple Pay API,支付¥" + amount);
            // 实际的Apple Pay支付逻辑
        } else {
            throw new IllegalArgumentException("不支持的支付方式: " + paymentType);
        }
        // 未来新增一种支付方式(如数字货币),就必须修改这个函数,增加一个else if分支
    }
}

问题:

  • 违反开闭原则​:每当需要增加一种新的支付方式(例如 unionPay(银联)或 digitalCurrency(数字货币)),你都必须修改这个 processPayment函数的内部逻辑,增加一个新的 else if分支。这违反了面向对象设计原则中的“对扩展开放,对修改关闭”的原则。

  • 代码臃肿,可读性差​:所有的支付逻辑都堆积在一个方法里。如果每种支付方式的逻辑都很复杂(例如涉及不同的参数组装、加密算法、第三方API调用),这个方法会变得非常长,难以阅读和理解。

  • 可维护性低​:不同支付方式的逻辑相互纠缠。修改一种支付方式的逻辑时,可能会无意中影响到其他支付方式的代码(虽然逻辑上独立,但物理上靠近,容易误触)。调试时也需要在这个庞大的函数中一步步跟踪。

  • 难以测试​:要为这个 processPayment方法编写单元测试,你需要覆盖所有的 if-else分支,测试用例会又长又复杂。你很难模拟(Mock)各种支付方式的具体实现,因为它们都紧耦合在这个方法里。

  • 重复代码​:如果其他业务逻辑(如退款、查询订单)也需要根据支付类型进行类似的判断,那么同样的 if-else语句可能会散布在代码库的多个地方,导致代码重复。

正确的使用样例步骤:

  1. 定义策略接口,策略接口共同方法
  2. 实现策略接口的具体实现类
  3. 定义工厂类,并设置缓存map(键为策略类型(即Bean名称),值为对应的策略实例)
  4. 可设置监控,控制策略的注册

策略接口

package com.luojie.strategy;

/**
 * 支付策略接口
 * <p>
 * 这是策略模式的核心接口,定义了所有支付策略必须实现的共同方法。
 * 通过这个接口,不同的支付方式可以被统一对待,实现了策略的封装和替换。
 * </p>
 * <p>
 * 在策略模式中,这个接口扮演了"策略"角色,定义了算法族的共同接口,
 * 任何具体的支付方式都需要实现这个接口,提供自己的支付逻辑。
 * </p>
 */
public interface PaymentStrategy {
    /**
     * 支付方法
     * <p>
     * 所有支付策略都必须实现的核心方法,用于执行具体的支付操作。
     * 不同的支付策略(如支付宝、微信支付、银联支付)会提供各自不同的实现。
     * </p>
     * @param amount 支付金额,使用double类型表示
     * @return 支付结果,返回一个描述支付过程的字符串信息
     */
    String pay(double amount);
}

策略实现类--支付宝

package com.luojie.strategy;

import org.springframework.stereotype.Component;

/**
 * 支付宝支付策略实现
 * <p>
 * 这是支付策略接口的具体实现类,专门处理支付宝支付逻辑。
 * 在策略模式中,这个类扮演了"具体策略"角色,实现了策略接口定义的算法。
 * </p>
 * <p>
 * 通过Spring的@Component注解将该类标记为Spring组件,
 * 并指定Bean名称为"alipay",这样策略工厂可以通过这个名称来获取该策略实例。
 * </p>
 */
@Component("alipay")  // 将该策略注册为Spring Bean,名称为"alipay"
public class AlipayStrategy implements PaymentStrategy {
    /**
     * 实现支付宝支付逻辑
     * <p>
     * 该方法提供了使用支付宝进行支付的具体实现。
     * 在实际应用中,这里会包含与支付宝API交互的代码,
     * 如构建支付请求、调用支付宝SDK、处理支付结果等。
     * </p>
     * <p>
     * 当前示例为了演示策略模式的基本结构,使用了简化的实现,
     * 仅返回一个描述支付过程的字符串。
     * </p>
     * @param amount 支付金额
     * @return 支付结果描述
     */
    @Override
    public String pay(double amount) {
        // 实际应用中,这里会包含真实的支付宝支付逻辑
        // 例如调用支付宝API、处理支付请求等
        return "使用支付宝支付了" + amount + "元";
    }
}

策略实现类--银联支付

package com.luojie.strategy;

import org.springframework.stereotype.Component;

/**
 * 银联支付策略实现
 * <p>
 * 这是支付策略接口的具体实现类,专门处理银联支付逻辑。
 * 在策略模式中,这个类扮演了"具体策略"角色,实现了策略接口定义的算法。
 * </p>
 * <p>
 * 通过Spring的@Component注解将该类标记为Spring组件,
 * 并指定Bean名称为"unionPay",这样策略工厂可以通过这个名称来获取该策略实例。
 * </p>
 */
@Component("unionPay")  // 将该策略注册为Spring Bean,名称为"unionPay"
public class UnionPayStrategy implements PaymentStrategy {
    /**
     * 实现银联支付逻辑
     * <p>
     * 该方法提供了使用银联支付进行支付的具体实现。
     * 在实际应用中,这里会包含与银联支付API交互的代码,
     * 如构建支付请求、调用银联支付SDK、处理支付结果等。
     * </p>
     * <p>
     * 当前示例为了演示策略模式的基本结构,使用了简化的实现,
     * 仅返回一个描述支付过程的字符串。
     * </p>
     * @param amount 支付金额
     * @return 支付结果描述
     */
    @Override
    public String pay(double amount) {
        // 实际应用中,这里会包含真实的银联支付逻辑
        // 例如调用银联支付API、处理支付请求等
        return "使用银联支付了" + amount + "元";
    }
}

策略实现类--微信支付

package com.luojie.strategy;

import org.springframework.stereotype.Component;

/**
 * 微信支付策略实现
 * <p>
 * 这是支付策略接口的具体实现类,专门处理微信支付逻辑。
 * 在策略模式中,这个类扮演了"具体策略"角色,实现了策略接口定义的算法。
 * </p>
 * <p>
 * 通过Spring的@Component注解将该类标记为Spring组件,
 * 并指定Bean名称为"wechatPay",这样策略工厂可以通过这个名称来获取该策略实例。
 * </p>
 */
@Component("wechatPay")  // 将该策略注册为Spring Bean,名称为"wechatPay"
public class WechatPayStrategy implements PaymentStrategy {
    /**
     * 实现微信支付逻辑
     * <p>
     * 该方法提供了使用微信支付进行支付的具体实现。
     * 在实际应用中,这里会包含与微信支付API交互的代码,
     * 如构建支付请求、调用微信支付SDK、处理支付结果等。
     * </p>
     * <p>
     * 当前示例为了演示策略模式的基本结构,使用了简化的实现,
     * 仅返回一个描述支付过程的字符串。
     * </p>
     * @param amount 支付金额
     * @return 支付结果描述
     */
    @Override
    public String pay(double amount) {
        // 实际应用中,这里会包含真实的微信支付逻辑
        // 例如调用微信支付API、处理支付请求等
        return "使用微信支付了" + amount + "元";
    }
}

工厂类

package com.luojie.strategy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.luojie.config.StrategyConfig.StrategyConfigurationInfo;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 支付策略工厂
 * <p>
 * 这是工厂模式与策略模式结合使用的核心类,负责管理和提供各种支付策略实例。
 * 在策略模式中,这个类扮演了"策略选择器"的角色,客户端通过工厂来获取具体策略,
 * 而不需要直接实例化具体策略类,从而实现了客户端与具体策略的解耦。
 * </p>
 * <p>
 * 通过Spring的依赖注入机制和StrategyConfigurationInfo配置,该工厂能够根据配置
 * 决定是否自动收集所有实现了PaymentStrategy接口的Bean,提供了更灵活的策略管理方式。
 * </p>
 */
@Component  // 注册为Spring组件,使其能够被自动发现和注入
public class PaymentStrategyFactory {
    // 日志记录器,用于记录工厂的操作日志
    private static final Logger logger = LoggerFactory.getLogger(PaymentStrategyFactory.class);
    
    // 使用ConcurrentHashMap存储所有策略实现,保证线程安全
    // 键为策略类型(即Bean名称),值为对应的策略实例
    private final Map<String, PaymentStrategy> strategyMap = new ConcurrentHashMap<>();
    
    // 注入策略配置信息,用于控制策略的自动注册行为
    private final StrategyConfigurationInfo configInfo;

    /**
     * 构造函数,注入策略配置信息和所有策略实现
     * <p>
     * 根据StrategyConfigurationInfo中的autoRegisterStrategies配置决定是否自动注册所有策略。
     * 这样可以灵活控制策略的管理方式。
     * </p>
     * @param strategyMap 包含所有策略实现的Map,由Spring自动注入
     * @param configInfo 策略配置信息,控制自动注册行为
     */
    @Autowired
    public PaymentStrategyFactory(Map<String, PaymentStrategy> strategyMap, 
                                 StrategyConfigurationInfo configInfo) {
        this.configInfo = configInfo;
        
        // 根据配置决定是否自动注册所有策略
        if (configInfo != null && configInfo.isAutoRegisterStrategies()) {
            this.strategyMap.putAll(strategyMap);
            // 记录策略注册信息,便于调试和监控
            logger.info("支付策略工厂初始化完成,共自动加载了{}种支付策略", strategyMap.size());
            logger.info("已加载的支付策略类型:{}", strategyMap.keySet());
        } else {
            logger.info("支付策略工厂初始化完成,策略自动注册功能已禁用");
        }
    }
    
    /**
     * 手动注册支付策略
     * <p>
     * 当autoRegisterStrategies设置为false时,可以通过此方法手动注册策略。
     * 这提供了更精细的策略管理控制。
     * </p>
     * @param strategyType 策略类型(唯一标识符)
     * @param strategy 策略实现实例
     * @return 当前工厂实例,支持链式调用
     */
    public PaymentStrategyFactory registerStrategy(String strategyType, PaymentStrategy strategy) {
        if (strategyType == null || strategy == null) {
            logger.error("注册策略失败:策略类型或策略实例不能为空");
            throw new IllegalArgumentException("策略类型或策略实例不能为空");
        }
        
        strategyMap.put(strategyType, strategy);
        logger.info("手动注册支付策略成功:{}", strategyType);
        return this;
    }
    
    /**
     * 移除已注册的支付策略
     * <p>
     * 提供移除策略的功能,便于动态调整可用的支付方式。
     * </p>
     * @param strategyType 要移除的策略类型
     * @return 被移除的策略实例,如果不存在则返回null
     */
    public PaymentStrategy unregisterStrategy(String strategyType) {
        PaymentStrategy removedStrategy = strategyMap.remove(strategyType);
        if (removedStrategy != null) {
            logger.info("移除支付策略成功:{}", strategyType);
        }
        return removedStrategy;
    }

    /**
     * 根据策略类型获取对应的策略实现
     * <p>
     * 这是工厂的核心方法,用于根据客户端提供的策略类型,返回对应的策略实例。
     * 客户端只需要知道策略类型(如"alipay"、"wechatPay"等),
     * 不需要知道具体的策略实现类,从而实现了客户端与具体策略的解耦。
     * </p>
     * @param strategyType 策略类型(即Bean名称)
     * @return 对应的策略实现实例
     * @throws IllegalArgumentException 如果请求的策略类型不存在
     */
    public PaymentStrategy getStrategy(String strategyType) {
        // 日志记录请求的策略类型
        logger.debug("请求获取支付策略:{}", strategyType);
        
        // 从Map中获取对应的策略实现
        PaymentStrategy strategy = strategyMap.get(strategyType);
        
        // 如果策略不存在,抛出异常
        if (strategy == null) {
            logger.error("不支持的支付方式:{}", strategyType);
            throw new IllegalArgumentException("不支持的支付方式:" + strategyType);
        }
        
        // 返回获取到的策略实例
        logger.debug("成功获取支付策略:{},对应的实现类:{}", 
                   strategyType, strategy.getClass().getSimpleName());
        return strategy;
    }
}

扩展的控制类

package com.luojie.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * 策略模式配置类
 * <p>
 * 该类是整个策略模式实现的核心配置类,主要负责:
 * 1. 启用策略包的组件扫描
 * 2. 配置策略监控机制
 * 3. 提供策略配置信息管理
 * <p>
 * 通过Spring的@Configuration注解标记为配置类,确保在Spring Boot应用启动时被自动加载
 * </p>
 */
@Configuration
// 主组件扫描由Spring Boot自动处理,这里使用StrategyConfigurationInfo中的packageToScan进行更灵活的配置
// @ComponentScan注解本身不支持动态路径,但我们在后续的BeanPostProcessor中使用packageToScan参数
public class StrategyConfig {
    // 日志记录器,使用SLF4J框架记录配置和监控信息
    private static final Logger logger = LoggerFactory.getLogger(StrategyConfig.class);

    /**
     * 构造函数,用于记录配置类初始化信息
     * <p>
     * 在配置类实例化时记录初始化日志,便于跟踪系统启动过程中的策略模式初始化状态
     * </p>
     */
    public StrategyConfig() {
        logger.info("策略模式配置类[StrategyConfig]初始化完成");
        logger.info("开始扫描策略包: com.luojie.strategy");
    }

    /**
     * 创建策略模式监控的BeanPostProcessor
     * <p>
     * 通过Spring的BeanPostProcessor机制,在所有Bean初始化完成后进行拦截处理,
     * 专门用于监控和记录策略实现类的加载情况,帮助开发者确认所有策略都已正确注册到Spring容器
     * </p>
     * @param strategyConfigurationInfo 策略配置信息,用于控制监控行为
     * @return 自定义的BeanPostProcessor实例,用于策略实现类的监控
     */
    @Bean
    public BeanPostProcessor strategyBeanPostProcessor(StrategyConfigurationInfo strategyConfigurationInfo) {
        return new BeanPostProcessor() {
            /**
             * 在Bean初始化完成后进行处理
             * <p>
             * 此方法会在每个Spring Bean初始化完成后被调用,我们在这里专门处理策略包中的Bean
             * </p>
             * @param bean 初始化完成的Bean实例
             * @param beanName Bean在Spring容器中的名称
             * @return 处理后的Bean实例(此处直接返回原实例,不做修改)
             * @throws BeansException Bean处理过程中的异常
             */
            @Override
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                // 根据配置信息决定是否启用监控
                if (strategyConfigurationInfo.isMonitorEnabled()) {
                    // 检查是否为支付策略实现类(排除配置类、工厂类和上下文类本身)
            // 使用配置中的packageToScan参数进行判断,实现动态配置
            if (bean.getClass().getPackage() != null && 
                strategyConfigurationInfo.getPackageToScan() != null &&
                bean.getClass().getPackage().getName().startsWith(strategyConfigurationInfo.getPackageToScan()) && 
                !beanName.equals("strategyConfig") && 
                !beanName.equals("paymentStrategyFactory") && 
                !beanName.equals("paymentContext")) {
                        // 记录策略实现类的初始化和注册信息
                        logger.info("策略实现类[{}] (Bean名称: {}) 初始化完成并注册到Spring容器", 
                                    bean.getClass().getSimpleName(), beanName);
                    }
                }
                return bean;  // 返回原Bean,不做任何修改
            }
        };
    }

    /**
     * 获取策略模式配置信息的方法
     * <p>
     * 创建并配置一个StrategyConfigurationInfo实例,用于封装当前策略模式的配置状态
     * 将其注册为Spring Bean,便于在系统其他地方获取和使用这些配置信息
     * </p>
     * <p>
     * 该配置实例包含三个核心参数,都有实际应用场景:
     * 1. packageToScan:用于策略实现类的包路径识别,在BeanPostProcessor中使用
     * 2. monitorEnabled:控制是否启用策略监控功能
     * 3. autoRegisterStrategies:控制策略工厂是否自动注册所有策略
     * </p>
     * @return 配置完成的StrategyConfigurationInfo实例
     */
    @Bean
    public StrategyConfigurationInfo strategyConfigurationInfo() {
        StrategyConfigurationInfo info = new StrategyConfigurationInfo();
        // 设置要扫描的策略包路径 - 用于BeanPostProcessor中的策略类识别
        info.setPackageToScan("com.luojie.strategy");
        // 启用策略监控功能 - 控制是否记录策略实现类的加载日志
        info.setMonitorEnabled(true);
        // 启用策略自动注册功能 - 控制策略工厂是否自动注册所有策略实现
        info.setAutoRegisterStrategies(true);
        // 记录配置信息日志
        logger.info("策略模式配置信息: {}", info);
        return info;
    }

    /**
     * 内部类,用于封装策略模式的配置信息
     * <p>
     * 该类作为StrategyConfig的内部类,专门用于封装和管理策略模式的配置参数,
     * 提供了对策略扫描、监控和自动注册等功能的配置管理
     * </p>
     */
    public static class StrategyConfigurationInfo {
        // 策略实现类所在的包路径,用于组件扫描
        private String packageToScan;
        // 是否启用策略监控功能
        private boolean monitorEnabled;
        // 是否自动注册策略实现到工厂类
        private boolean autoRegisterStrategies;

        /**
         * 获取策略实现类所在的包路径
         * @return 包路径字符串
         */
        public String getPackageToScan() {
            return packageToScan;
        }

        /**
         * 设置策略实现类所在的包路径
         * @param packageToScan 包路径字符串
         */
        public void setPackageToScan(String packageToScan) {
            this.packageToScan = packageToScan;
        }

        /**
         * 获取是否启用策略监控功能
         * @return true表示启用监控,false表示禁用监控
         */
        public boolean isMonitorEnabled() {
            return monitorEnabled;
        }

        /**
         * 设置是否启用策略监控功能
         * @param monitorEnabled true表示启用监控,false表示禁用监控
         */
        public void setMonitorEnabled(boolean monitorEnabled) {
            this.monitorEnabled = monitorEnabled;
        }

        /**
         * 获取是否自动注册策略实现
         * @return true表示自动注册,false表示手动注册
         */
        public boolean isAutoRegisterStrategies() {
            return autoRegisterStrategies;
        }

        /**
         * 设置是否自动注册策略实现
         * @param autoRegisterStrategies true表示自动注册,false表示手动注册
         */
        public void setAutoRegisterStrategies(boolean autoRegisterStrategies) {
            this.autoRegisterStrategies = autoRegisterStrategies;
        }

        /**
         * 返回配置信息的字符串表示
         * @return 包含所有配置项的字符串
         */
        @Override
        public String toString() {
            return "StrategyConfigurationInfo{" +
                    "packageToScan='" + packageToScan + '\'' +
                    ", monitorEnabled=" + monitorEnabled +
                    ", autoRegisterStrategies=" + autoRegisterStrategies +
                    '}';
        }
    }
}

实际的调用类--根据type,直接调用具体的对象方法

package com.luojie.strategy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 支付上下文类
 * <p>
 * 这是策略模式中的上下文类,负责持有和使用策略,为客户端提供统一的调用入口。
 * 在策略模式中,上下文类封装了策略的选择和使用细节,客户端不需要直接与策略交互,
 * 只需与上下文类交互即可,从而进一步降低了客户端与具体策略的耦合。
 * </p>
 * <p>
 * 该上下文类提供了两种使用策略的方式:
 * 1. 先设置策略,然后执行操作(分步式)
 * 2. 直接指定策略类型执行操作(一步式)
 * </p>
 */
@Component  // 注册为Spring组件,使其能够被自动发现和注入
public class PaymentContext {
    // 日志记录器,用于记录上下文的操作日志
    private static final Logger logger = LoggerFactory.getLogger(PaymentContext.class);
    
    // 策略工厂,用于获取具体的策略实例
    private final PaymentStrategyFactory paymentStrategyFactory;
    // 当前使用的支付策略实例
    private PaymentStrategy currentStrategy;

    /**
     * 构造函数,注入策略工厂
     * <p>
     * 通过Spring的依赖注入机制,自动获取PaymentStrategyFactory的实例,
     * 以便后续通过工厂获取具体的策略实现。
     * </p>
     * @param paymentStrategyFactory 支付策略工厂实例
     */
    @Autowired
    public PaymentContext(PaymentStrategyFactory paymentStrategyFactory) {
        this.paymentStrategyFactory = paymentStrategyFactory;
        logger.info("支付上下文初始化完成");
    }

    /**
     * 设置支付策略
     * <p>
     * 这是分步式使用策略的第一步,用于设置后续操作要使用的支付策略。
     * 通过策略工厂获取指定类型的策略实例,并存储在当前上下文中。
     * </p>
     * @param strategyType 策略类型(如"alipay"、"wechatPay"等)
     */
    public void setPaymentStrategy(String strategyType) {
        logger.debug("设置支付策略:{}", strategyType);
        this.currentStrategy = paymentStrategyFactory.getStrategy(strategyType);
        logger.info("支付策略设置成功:{}", strategyType);
    }

    /**
     * 执行支付操作
     * <p>
     * 这是分步式使用策略的第二步,使用已设置的支付策略执行支付操作。
     * 在调用此方法前,必须先调用setPaymentStrategy方法设置策略。
     * </p>
     * @param amount 支付金额
     * @return 支付结果描述
     * @throws IllegalStateException 如果未设置支付策略
     */
    public String executePayment(double amount) {
        // 检查是否已设置支付策略
        if (currentStrategy == null) {
            logger.error("执行支付失败:未设置支付策略");
            throw new IllegalStateException("请先设置支付策略");
        }
        
        logger.debug("执行支付操作,金额:{}元,使用策略:{}", 
                    amount, currentStrategy.getClass().getSimpleName());
        
        // 调用当前策略的pay方法执行支付
        String result = currentStrategy.pay(amount);
        
        logger.info("支付操作执行完成,结果:{}", result);
        return result;
    }

    /**
     * 直接执行支付,一步完成策略选择和支付操作
     * <p>
     * 这是一步式使用策略的方法,将策略选择和执行操作合并为一步,
     * 适用于只需单次使用特定策略的场景,无需先设置再执行。
     * </p>
     * @param strategyType 策略类型(如"alipay"、"wechatPay"等)
     * @param amount 支付金额
     * @return 支付结果描述
     */
    public String pay(String strategyType, double amount) {
        logger.debug("直接执行支付,策略类型:{},金额:{}元", strategyType, amount);
        
        // 通过工厂获取指定的策略实例并直接调用其pay方法
        PaymentStrategy strategy = paymentStrategyFactory.getStrategy(strategyType);
        String result = strategy.pay(amount);
        
        logger.info("直接支付操作执行完成,结果:{}", result);
        return result;
    }
}

调用测试


网站公告

今日签到

点亮在社区的每一天
去签到