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. 里氏替换:任何策略都可替换为其他实现,不影响客户端使用。
相关推荐
阿宁又菜又爱玩6 小时前
Maven基础知识
java·maven
S***q3776 小时前
【Springboot】@Autowired和@Resource的区别
java·spring boot·mybatis
老王熬夜敲代码6 小时前
泛型编程的差异抽象思想
开发语言·c++·笔记
南部余额6 小时前
SpringBoot自定义场景启动器
java·spring boot·场景启动器
p***s916 小时前
【SpringBoot】日志文件
java·spring boot·spring
zqy02276 小时前
python安装与环境配置
开发语言·python
z***D6486 小时前
SpringBoot 新特性
java·spring boot·后端
冷雨夜中漫步6 小时前
Maven BOM(Bill of Materials)使用指南与常见错误
java·数据库·maven
客梦6 小时前
Java教室管理系统
java·笔记