十三、行为型(策略模式)

策略模式(Strategy Pattern)

概念

策略模式(Strategy Pattern)是一种行为型设计模式,允许定义一系列算法,将每个算法封装在策略类中,并使它们可以互换使用。客户端可以根据需要动态选择不同的策略对象,从而在运行时决定采用哪种具体算法。


应用场景

  1. 算法的可替换性:当系统有多个不同的算法且这些算法可以互相替换时,可以使用策略模式。例如,排序算法、压缩算法等不同算法的实现。

  2. 避免条件分支 :当系统中存在大量的if-elseswitch-case语句以选择不同的算法或行为时,可以使用策略模式将这些条件分支移入不同的策略类中,减少代码复杂度。

  3. 动态地选择行为:策略模式允许在运行时动态地选择或切换不同的算法或行为。例如,支付系统中可以选择不同的支付方式(如信用卡、支付宝、微信等)作为策略。

  4. 解耦行为与使用者:策略模式使得具体的算法实现与使用算法的类解耦,使用者无需了解具体的算法实现,只需使用策略接口即可。


注意点

  • 策略的数量:随着算法或行为的增加,策略类的数量也会增加,可能会造成类数量的膨胀。
  • 策略的独立性:策略类应当是独立的,相互之间不应依赖。如果策略之间有逻辑关系,可能需要进一步重构。
  • 客户端必须知晓策略:客户端需要了解并决定使用哪种策略,可能增加其复杂度。

核心要素

  1. Strategy(策略接口):定义一系列可供选择的算法或行为。
  2. ConcreteStrategy(具体策略):具体的算法实现类,每个策略类实现不同的算法。
  3. Context(上下文类):维护一个策略对象,并根据客户端的选择动态使用不同的策略。

Java代码完整示例

代码示例:简单策略模式

java 复制代码
// 定义策略接口
interface Strategy {
    void execute();
}

// 具体策略类 A
class ConcreteStrategyA implements Strategy {
    @Override
    public void execute() {
        System.out.println("使用策略A进行操作");
    }
}

// 具体策略类 B
class ConcreteStrategyB implements Strategy {
    @Override
    public void execute() {
        System.out.println("使用策略B进行操作");
    }
}

// 上下文类,维护一个策略对象
class Context {
    private Strategy strategy;

    // 构造函数注入策略对象
    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    // 动态设置策略
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    // 执行策略
    public void executeStrategy() {
        strategy.execute();
    }
}

// 客户端代码
public class StrategyPatternDemo {
    public static void main(String[] args) {
        // 使用策略A
        Context context = new Context(new ConcreteStrategyA());
        context.executeStrategy();

        // 切换到策略B
        context.setStrategy(new ConcreteStrategyB());
        context.executeStrategy();
    }
}

输出结果

使用策略A进行操作
使用策略B进行操作

各种变形用法完整示例

  1. 策略模式结合枚举

    通过枚举来实现策略模式,每个枚举实例代表一种策略。

    代码示例

    java 复制代码
    enum PaymentStrategy {
        CREDIT_CARD {
            @Override
            public void pay(double amount) {
                System.out.println("使用信用卡支付: " + amount + " 元");
            }
        },
        PAYPAL {
            @Override
            public void pay(double amount) {
                System.out.println("使用PayPal支付: " + amount + " 元");
            }
        },
        ALIPAY {
            @Override
            public void pay(double amount) {
                System.out.println("使用支付宝支付: " + amount + " 元");
            }
        };
    
        public abstract void pay(double amount);
    }
    
    public class PaymentContext {
        private PaymentStrategy strategy;
    
        public PaymentContext(PaymentStrategy strategy) {
            this.strategy = strategy;
        }
    
        public void setStrategy(PaymentStrategy strategy) {
            this.strategy = strategy;
        }
    
        public void pay(double amount) {
            strategy.pay(amount);
        }
    
        public static void main(String[] args) {
            PaymentContext context = new PaymentContext(PaymentStrategy.CREDIT_CARD);
            context.pay(100.0);
    
            context.setStrategy(PaymentStrategy.PAYPAL);
            context.pay(200.0);
    
            context.setStrategy(PaymentStrategy.ALIPAY);
            context.pay(300.0);
        }
    }

    输出结果

    使用信用卡支付: 100.0 元
    使用PayPal支付: 200.0 元
    使用支付宝支付: 300.0 元
    
  2. 策略模式结合Lambda表达式

    在Java 8中,可以使用Lambda表达式简化策略模式的实现,将策略作为函数式接口来处理。

    代码示例

    java 复制代码
    interface Strategy {
        void execute();
    }
    
    public class StrategyLambdaDemo {
        public static void main(String[] args) {
            // 使用Lambda表达式定义不同策略
            Strategy strategyA = () -> System.out.println("使用策略A执行操作");
            Strategy strategyB = () -> System.out.println("使用策略B执行操作");
    
            // 创建上下文并设置策略
            Context context = new Context(strategyA);
            context.executeStrategy();
    
            context.setStrategy(strategyB);
            context.executeStrategy();
        }
    }

    输出结果

    使用策略A执行操作
    使用策略B执行操作
    
  3. 策略模式结合工厂模式

    可以通过工厂模式来创建不同的策略对象,并根据条件动态选择合适的策略。

    代码示例

    java 复制代码
    // 定义策略接口
    interface Strategy {
        void execute();
    }
    
    // 具体策略类 A
    class ConcreteStrategyA implements Strategy {
        @Override
        public void execute() {
            System.out.println("使用策略A进行操作");
        }
    }
    
    // 具体策略类 B
    class ConcreteStrategyB implements Strategy {
        @Override
        public void execute() {
            System.out.println("使用策略B进行操作");
        }
    }
    
    // 策略工厂类
    class StrategyFactory {
        public static Strategy getStrategy(String type) {
            switch (type) {
                case "A":
                    return new ConcreteStrategyA();
                case "B":
                    return new ConcreteStrategyB();
                default:
                    throw new IllegalArgumentException("未知策略类型");
            }
        }
    }
    
    // 上下文类
    class Context {
        private Strategy strategy;
    
        public Context(Strategy strategy) {
            this.strategy = strategy;
        }
    
        public void executeStrategy() {
            strategy.execute();
        }
    }
    
    // 客户端
    public class StrategyFactoryDemo {
        public static void main(String[] args) {
            // 通过工厂创建策略对象
            Context context = new Context(StrategyFactory.getStrategy("A"));
            context.executeStrategy();
    
            context = new Context(StrategyFactory.getStrategy("B"));
            context.executeStrategy();
        }
    }

    输出结果

    使用策略A进行操作
    使用策略B进行操作
    
  4. 策略模式结合依赖注入

    使用依赖注入框架(如Spring)动态选择策略,这样可以将策略的选择交给框架来管理。

    代码示例(伪代码)

    java 复制代码
    // 定义策略接口
    interface Strategy {
        void execute();
    }
    
    // 具体策略类 A
    @Component("strategyA")
    class ConcreteStrategyA implements Strategy {
        @Override
        public void execute() {
            System.out.println("使用策略A进行操作");
        }
    }
    
    // 具体策略类 B
    @Component("strategyB")
    class ConcreteStrategyB implements Strategy {
        @Override
        public void execute() {
            System.out.println("使用策略B进行操作");
        }
    }
    
    // 上下文类
    @Component
    class Context {
        private final Map<String, Strategy> strategies;
    
        // 使用Spring自动注入策略Map
        public Context(Map<String, Strategy> strategies) {
            this.strategies = strategies;
        }
    
        public void executeStrategy(String strategyType) {
            Strategy strategy = strategies.get(strategyType);
            if (strategy != null) {
                strategy.execute();
            } else {
                throw new IllegalArgumentException("未知策略类型");
            }
        }
    }
    
    // 客户端
    @SpringBootApplication
    public class StrategySpringDemo {
        public static void main(String[] args) {
            ApplicationContext context = SpringApplication.run(StrategySpringDemo.class, args);
            Context strategyContext = context.getBean(Context.class);
    
            strategyContext.executeStrategy("strategyA");
            strategyContext.executeStrategy("strategyB");
        }
    }

    输出结果

    使用策略A进行操作
    使用策略B进行操作
    

通过这些不同的变形,策略模式不仅能应对多种不同的需求场景,还能与现代开发方法(如枚举、Lambda、工厂模式、依赖注入等)灵活结合,进一步提升代码的可维护性和可扩展性。

相关推荐
ZSYP-S9 分钟前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
yuanbenshidiaos12 分钟前
c++------------------函数
开发语言·c++
程序员_三木24 分钟前
Three.js入门-Raycaster鼠标拾取详解与应用
开发语言·javascript·计算机外设·webgl·three.js
是小崔啊34 分钟前
开源轮子 - EasyExcel01(核心api)
java·开发语言·开源·excel·阿里巴巴
tianmu_sama40 分钟前
[Effective C++]条款38-39 复合和private继承
开发语言·c++
黄公子学安全43 分钟前
Java的基础概念(一)
java·开发语言·python
liwulin050644 分钟前
【JAVA】Tesseract-OCR截图屏幕指定区域识别0.4.2
java·开发语言·ocr
jackiendsc1 小时前
Java的垃圾回收机制介绍、工作原理、算法及分析调优
java·开发语言·算法
Oneforlove_twoforjob1 小时前
【Java基础面试题027】Java的StringBuilder是怎么实现的?
java·开发语言
羚羊角uou1 小时前
【C++】优先级队列以及仿函数
开发语言·c++