JAVA中六种策略模式的实现

在 Java 中,策略模式的核心是定义算法族、封装算法、动态切换,其实现方式主要围绕 "策略的定义、创建、选择" 展开,根据场景复杂度和技术选型,常见有以下 6 种实现方式,附代码示例和适用场景:

一、基础实现:接口 + 实现类(经典方式)

最标准的实现,通过接口定义策略契约,多个实现类封装不同算法,客户端通过注入或选择不同实现类切换策略。

代码示例
java 复制代码
// 1. 策略接口(定义契约)
public interface PaymentStrategy {
    // 策略核心方法:支付
    boolean pay(double amount);
    // 获取策略名称
    String getStrategyName();
}

// 2. 具体策略1:支付宝支付
public class AlipayStrategy implements PaymentStrategy {
    @Override
    public boolean pay(double amount) {
        System.out.println("使用支付宝支付:" + amount + "元");
        return true; // 模拟支付成功
    }

    @Override
    public String getStrategyName() {
        return "alipay";
    }
}

// 3. 具体策略2:微信支付
public class WechatPayStrategy implements PaymentStrategy {
    @Override
    public boolean pay(double amount) {
        System.out.println("使用微信支付:" + amount + "元");
        return true;
    }

    @Override
    public String getStrategyName() {
        return "wechat";
    }
}

// 4. 策略上下文(封装策略,对外提供统一接口)
public class PaymentContext {
    private PaymentStrategy strategy;

    // 构造器注入策略
    public PaymentContext(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    // 动态切换策略
    public void setStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    // 客户端调用入口
    public boolean executePayment(double amount) {
        return strategy.pay(amount);
    }
}

// 5. 客户端使用
public class Client {
    public static void main(String[] args) {
        // 选择支付宝策略
        PaymentContext context = new PaymentContext(new AlipayStrategy());
        context.executePayment(100);

        // 动态切换为微信策略
        context.setStrategy(new WechatPayStrategy());
        context.executePayment(200);
    }
}
适用场景
  • 策略数量固定、变化不频繁(如支付方式、排序算法)。
  • 需明确暴露所有策略,允许客户端直接选择。

二、枚举实现(简化策略管理)

用枚举封装所有策略,利用枚举的 "单例特性" 和 "天然分组" 优势,减少类冗余,简化策略选择。

代码示例
java 复制代码
// 1. 枚举策略(实现策略逻辑)
public enum PaymentStrategyEnum {
    // 支付宝策略
    ALIPAY {
        @Override
        public boolean pay(double amount) {
            System.out.println("枚举-支付宝支付:" + amount + "元");
            return true;
        }
    },
    // 微信支付策略
    WECHAT {
        @Override
        public boolean pay(double amount) {
            System.out.println("枚举-微信支付:" + amount + "元");
            return true;
        }
    };

    // 策略核心方法(枚举抽象方法)
    public abstract boolean pay(double amount);
}

// 2. 客户端使用(直接通过枚举选择策略)
public class Client {
    public static void main(String[] args) {
        // 根据枚举值选择策略
        PaymentStrategyEnum.ALIPAY.pay(100);
        PaymentStrategyEnum.WECHAT.pay(200);

        // 支持动态传入策略(如从配置文件读取)
        String strategyName = "ALIPAY"; // 可来自配置
        PaymentStrategyEnum strategy = Enum.valueOf(PaymentStrategyEnum.class, strategyName);
        strategy.pay(300);
    }
}
适用场景
  • 策略数量少、逻辑简单(如状态判断、固定规则)。
  • 无需动态扩展策略(枚举不可动态新增)。

三、工厂模式 + 策略模式(解耦策略创建)

通过工厂类封装策略的创建逻辑,客户端无需关注策略的实例化细节,只需传入标识即可获取对应策略,适合策略较多的场景。

代码示例
java 复制代码
// 1. 策略接口(同基础实现)
public interface PaymentStrategy {
    boolean pay(double amount);
    String getStrategyCode();
}

// 2. 具体策略(同基础实现:AlipayStrategy、WechatPayStrategy)

// 3. 策略工厂(封装策略创建)
public class PaymentStrategyFactory {
    // 缓存策略实例(单例)
    private static final Map<String, PaymentStrategy> STRATEGY_MAP = new HashMap<>();

    // 静态初始化:注册所有策略
    static {
        STRATEGY_MAP.put("alipay", new AlipayStrategy());
        STRATEGY_MAP.put("wechat", new WechatPayStrategy());
    }

    // 禁止外部实例化
    private PaymentStrategyFactory() {}

    // 根据标识获取策略
    public static PaymentStrategy getStrategy(String strategyCode) {
        PaymentStrategy strategy = STRATEGY_MAP.get(strategyCode);
        if (strategy == null) {
            throw new IllegalArgumentException("不支持的支付方式:" + strategyCode);
        }
        return strategy;
    }

    // 扩展:动态注册新策略(支持热更新)
    public static void registerStrategy(String code, PaymentStrategy strategy) {
        STRATEGY_MAP.put(code, strategy);
    }
}

// 4. 客户端使用
public class Client {
    public static void main(String[] args) {
        // 从工厂获取策略(无需手动new)
        PaymentStrategy alipay = PaymentStrategyFactory.getStrategy("alipay");
        alipay.pay(100);

        PaymentStrategy wechat = PaymentStrategyFactory.getStrategy("wechat");
        wechat.pay(200);

        // 动态注册新策略(如新增银联支付)
        PaymentStrategyFactory.registerStrategy("unionpay", new UnionPayStrategy());
        PaymentStrategyFactory.getStrategy("unionpay").pay(300);
    }
}

// 新增策略:银联支付(无需修改工厂核心逻辑)
class UnionPayStrategy implements PaymentStrategy {
    @Override
    public boolean pay(double amount) {
        System.out.println("使用银联支付:" + amount + "元");
        return true;
    }

    @Override
    public String getStrategyCode() {
        return "unionpay";
    }
}
适用场景
  • 策略数量多(如 10+),需要统一管理创建逻辑。
  • 客户端只需通过标识(如字符串、枚举)选择策略,无需关注实现。

四、注解 + 反射(动态扫描策略)

通过自定义注解标记策略类,程序启动时扫描所有带注解的策略并注册到工厂,支持 "无侵入式扩展"(新增策略无需修改工厂代码)。

代码示例
java 复制代码
// 1. 自定义策略注解(标记策略标识)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PaymentStrategyAnnotation {
    String code(); // 策略唯一标识
}

// 2. 策略接口(同基础实现)
public interface PaymentStrategy {
    boolean pay(double amount);
}

// 3. 具体策略(用注解标记)
@PaymentStrategyAnnotation(code = "alipay")
public class AlipayStrategy implements PaymentStrategy {
    @Override
    public boolean pay(double amount) {
        System.out.println("注解-支付宝支付:" + amount + "元");
        return true;
    }
}

@PaymentStrategyAnnotation(code = "wechat")
public class WechatPayStrategy implements PaymentStrategy {
    @Override
    public boolean pay(double amount) {
        System.out.println("注解-微信支付:" + amount + "元");
        return true;
    }
}

// 4. 策略工厂(反射扫描注解策略)
public class AnnotationStrategyFactory {
    private static final Map<String, PaymentStrategy> STRATEGY_MAP = new HashMap<>();

    // 初始化:扫描指定包下的所有策略
    static {
        try {
            // 扫描com.example.strategy包下的所有类
            Reflections reflections = new Reflections("com.example.strategy");
            // 获取所有带@PaymentStrategyAnnotation注解的类
            Set<Class<?>> strategyClasses = reflections.getTypesAnnotatedWith(PaymentStrategyAnnotation.class);

            // 实例化并注册策略
            for (Class<?> clazz : strategyClasses) {
                PaymentStrategyAnnotation annotation = clazz.getAnnotation(PaymentStrategyAnnotation.class);
                String code = annotation.code();
                PaymentStrategy strategy = (PaymentStrategy) clazz.newInstance();
                STRATEGY_MAP.put(code, strategy);
            }
        } catch (Exception e) {
            throw new RuntimeException("策略初始化失败", e);
        }
    }

    // 获取策略
    public static PaymentStrategy getStrategy(String code) {
        return STRATEGY_MAP.getOrDefault(code, () -> {
            System.out.println("默认策略:支付失败");
            return false;
        });
    }
}

// 5. 客户端使用(依赖Reflections库,需导入依赖)
public class Client {
    public static void main(String[] args) {
        AnnotationStrategyFactory.getStrategy("alipay").pay(100);
        AnnotationStrategyFactory.getStrategy("wechat").pay(200);
    }
}
依赖说明

需导入反射扫描库(Maven):

XML 复制代码
<dependency>
    <groupId>org.reflections</groupId>
    <artifactId>reflections</artifactId>
    <version>0.10.2</version>
</dependency>
适用场景
  • 大型项目,策略频繁新增(如插件化架构)。
  • 追求 "开闭原则",新增策略无需修改现有代码。

五、Lambda 表达式(简化无状态策略)

对于无状态、逻辑简单的策略,可直接用 Lambda 表达式实现策略接口,无需创建单独的实现类,简化代码。

代码示例
java 复制代码
// 1. 函数式策略接口(仅含一个抽象方法)
@FunctionalInterface
public interface PaymentStrategy {
    boolean pay(double amount);
}

// 2. 策略上下文(同基础实现)
public class PaymentContext {
    private PaymentStrategy strategy;

    public PaymentContext(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    public boolean execute(double amount) {
        return strategy.pay(amount);
    }
}

// 3. 客户端使用(Lambda直接实现策略)
public class Client {
    public static void main(String[] args) {
        // Lambda实现支付宝策略
        PaymentContext alipayContext = new PaymentContext(amount -> {
            System.out.println("Lambda-支付宝支付:" + amount + "元");
            return true;
        });
        alipayContext.execute(100);

        // Lambda实现微信策略
        PaymentContext wechatContext = new PaymentContext(amount -> {
            System.out.println("Lambda-微信支付:" + amount + "元");
            return true;
        });
        wechatContext.execute(200);

        // 甚至可以直接传递Lambda,无需上下文
        PaymentStrategy unionPay = amount -> {
            System.out.println("Lambda-银联支付:" + amount + "元");
            return true;
        };
        unionPay.pay(300);
    }
}
适用场景
  • 策略逻辑简单(1-3 行代码)、无状态(无需成员变量)。
  • 临时策略(仅使用一次),无需复用。

六、Spring 容器整合(依赖注入 + 自动装配)

在 Spring 项目中,利用 Spring 的 IOC 容器管理策略实例,通过@Autowired自动注入所有策略,结合MapList实现策略选择,无需手动创建工厂。

代码示例
java 复制代码
// 1. 策略接口(同基础实现)
public interface PaymentStrategy {
    boolean pay(double amount);
    String getStrategyCode();
}

// 2. 具体策略(Spring组件)
@Component // 交给Spring管理
public class AlipayStrategy implements PaymentStrategy {
    @Override
    public boolean pay(double amount) {
        System.out.println("Spring-支付宝支付:" + amount + "元");
        return true;
    }

    @Override
    public String getStrategyCode() {
        return "alipay";
    }
}

@Component
public class WechatPayStrategy implements PaymentStrategy {
    @Override
    public boolean pay(double amount) {
        System.out.println("Spring-微信支付:" + amount + "元");
        return true;
    }

    @Override
    public String getStrategyCode() {
        return "wechat";
    }
}

// 3. 策略服务(Spring组件,自动注入所有策略)
@Service
public class PaymentService {
    // Spring会自动将所有PaymentStrategy实现类注入到Map中:key=beanName,value=策略实例
    @Autowired
    private Map<String, PaymentStrategy> strategyMap;

    // 或按策略code映射(自定义key)
    private Map<String, PaymentStrategy> codeToStrategyMap;

    // 初始化:将策略按code分组
    @PostConstruct
    public void init() {
        codeToStrategyMap = strategyMap.values().stream()
                .collect(Collectors.toMap(PaymentStrategy::getStrategyCode, s -> s));
    }

    // 执行策略
    public boolean executePayment(String strategyCode, double amount) {
        PaymentStrategy strategy = codeToStrategyMap.get(strategyCode);
        if (strategy == null) {
            throw new IllegalArgumentException("不支持的支付方式");
        }
        return strategy.pay(amount);
    }
}

// 4. 客户端使用(Spring环境)
@SpringBootApplication
public class StrategyApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(StrategyApplication.class, args);
        PaymentService paymentService = context.getBean(PaymentService.class);

        paymentService.executePayment("alipay", 100);
        paymentService.executePayment("wechat", 200);
    }
}
适用场景
  • Spring Boot/Spring MVC 项目(充分利用 Spring 的 IOC 特性)。
  • 策略需要依赖其他 Spring 组件(如@Autowired数据源、缓存等)。

六种实现方式对比

实现方式 优点 缺点 适用场景
接口 + 实现类(经典) 结构清晰、易理解 策略多时有类爆炸问题 策略少、变化不频繁
枚举实现 代码简洁、无类冗余 策略逻辑复杂时不适用,不可动态扩展 策略少、逻辑简单
工厂 + 策略 解耦创建逻辑、支持动态扩展 新增策略需修改工厂注册代码 策略较多、需要统一管理
注解 + 反射 无侵入扩展、支持插件化 依赖反射库、初始化开销略大 大型项目、策略频繁新增
Lambda 表达式 代码极简、无需创建类 无状态、逻辑简单场景受限 临时策略、简单逻辑
Spring 整合 自动注入、支持依赖管理 依赖 Spring 环境 Spring 项目、策略需依赖其他组件

核心设计原则

无论哪种实现方式,都需遵循:

  1. 开闭原则:新增策略无需修改现有代码(枚举方式除外)。
  2. 单一职责:每个策略只负责一种算法,上下文只负责协调策略。
  3. 里氏替换:任何策略都可替换为其他实现,不影响客户端使用。
相关推荐
Slow菜鸟1 小时前
Java后端常用技术选型 |(五)可视化工具篇
java
青衫码上行1 小时前
【Java Web学习 | 第十篇】JavaScript(4) 对象
java·开发语言·前端·javascript·学习
q***69772 小时前
快速在本地运行SpringBoot项目的流程介绍
java·spring boot·后端
禁默2 小时前
基于Rust实现爬取 GitHub Trending 热门仓库
开发语言·rust·github
大邳草民2 小时前
深入理解 Python 的属性化方法
开发语言·笔记·python
随缘体验官2 小时前
【无标题】测试一下
java
.柒宇.2 小时前
力扣hoT100之找到字符串中所有字母异位词(java版)
java·数据结构·算法·leetcode
胎粉仔2 小时前
Swift 初阶 —— Sendable 协议 & data races
开发语言·ios·swift·sendable·并发域·data races
拂晓银砾3 小时前
Java 连接数据库
java