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

server/2024/10/20 16:54:28/

策略模式(Strategy Pattern)

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


应用场景

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

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

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

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


注意点

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

核心要素

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

Java代码完整示例

代码示例:简单策略模式

// 定义策略接口
interface Strategy {void execute();
}// 具体策略类 A
class ConcreteStrategyA implements Strategy {@Overridepublic void execute() {System.out.println("使用策略A进行操作");}
}// 具体策略类 B
class ConcreteStrategyB implements Strategy {@Overridepublic 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) {// 使用策略AContext context = new Context(new ConcreteStrategyA());context.executeStrategy();// 切换到策略Bcontext.setStrategy(new ConcreteStrategyB());context.executeStrategy();}
}

输出结果

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

各种变形用法完整示例

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

    代码示例

    enum PaymentStrategy {CREDIT_CARD {@Overridepublic void pay(double amount) {System.out.println("使用信用卡支付: " + amount + " 元");}},PAYPAL {@Overridepublic void pay(double amount) {System.out.println("使用PayPal支付: " + amount + " 元");}},ALIPAY {@Overridepublic 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表达式简化策略模式的实现,将策略作为函数式接口来处理。

    代码示例

    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. 策略模式结合工厂模式
    可以通过工厂模式来创建不同的策略对象,并根据条件动态选择合适的策略。

    代码示例

    // 定义策略接口
    interface Strategy {void execute();
    }// 具体策略类 A
    class ConcreteStrategyA implements Strategy {@Overridepublic void execute() {System.out.println("使用策略A进行操作");}
    }// 具体策略类 B
    class ConcreteStrategyB implements Strategy {@Overridepublic 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)动态选择策略,这样可以将策略的选择交给框架来管理。

    代码示例(伪代码)

    // 定义策略接口
    interface Strategy {void execute();
    }// 具体策略类 A
    @Component("strategyA")
    class ConcreteStrategyA implements Strategy {@Overridepublic void execute() {System.out.println("使用策略A进行操作");}
    }// 具体策略类 B
    @Component("strategyB")
    class ConcreteStrategyB implements Strategy {@Overridepublic void execute() {System.out.println("使用策略B进行操作");}
    }// 上下文类
    @Component
    class Context {private final Map<String, Strategy> strategies;// 使用Spring自动注入策略Mappublic 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、工厂模式、依赖注入等)灵活结合,进一步提升代码的可维护性和可扩展性。


http://www.ppmy.cn/server/133393.html

相关文章

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-16

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-16 目录 文章目录 目录1. Leveraging Social Determinants of Health in Alzheimers Research Using LLM-Augmented Literature Mining and Knowledge Graphs2. Alignment Between the Decision-Making Logic of …

Qt | CMake(Qt5 VS Qt6)

点击上方"蓝字"关注我们 01、CMake >>> CMake是一个简化跨不同平台开发项目构建过程的工具。CMake自动生成生成系统,如Makefiles和Visual Studio项目文件。 CMake是一个自带的第三方工具证明文件。 CMake 备忘清单02、如何使用CMake3.1.0带Qt 5 >>&…

【Golang】踩坑记录:make()创建引用类型,初始值是不是nil!!

文章目录 起因二、得记住的知识点1. make()切片&#xff0c;初始化了吗&#xff1f;2. make()切片不同长度容量&#xff0c;append时的差别3. 切片是指向数组的指针吗&#xff1f;4. 切片扩容时&#xff0c;重新分配内存&#xff0c;原切片的数据怎么办&#xff1f; 三、咳咳&a…

blender 金币基站 建模 学习笔记

一、学习blender视频教程链接 案例3&#xff1a;金币基站_建模_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Bt4y1E7qn?vd_sourced0ea58f1127eed138a4ba5421c577eb1&p12&spm_id_from333.788.videopod.episodes 二、金币基站建模过程 &#xff08;1&#x…

Spring AI Java程序员的AI之Spring AI(三)RAG实战

Spring AI之RAG实战与原理分析 前言RAGDocumentDocumentReaderDocumentTransformerDocumentWriter VectorStoreSimpleVectorStoreRedisVectorStore元数据搜索组装提示词 前言 检索增强生成&#xff08;RAG&#xff09;是一种结合信息检索和生成模型的技术&#xff0c;用于将相…

MYSQL 学习(四):数据库管理

MYSQL 学习&#xff08;四&#xff09;&#xff1a;数据库管理 文章目录 MYSQL 学习&#xff08;四&#xff09;&#xff1a;数据库管理1. 数据库表的创建与管理1.1 创建数据库命名规范创建语法 1.2 管理语法 2. 创建和管理表2.1 创建语法结构2.2 基于现有表创建表2.3 查看表结…

chat_gpt回答:python从bin文件里读四字节整型

要从一个二进制文件&#xff08;.bin 文件&#xff09;中读取四字节的整型数值&#xff0c;你可以使用 Python 的 struct 模块&#xff0c;这个模块专门用于处理二进制数据的打包和解包。 下面是一个简单的示例&#xff0c;展示如何从二进制文件中读取四字节整型&#xff1a; …

【代理模式使用场景】

一般来说&#xff0c;代理模式使用场景是远程代理、虚拟代理、安全代理等。下面来详细介绍下这三个场景是什么&#xff0c;实现原理和特点。不过在介绍三个场景前&#xff0c;我们还是先来回顾下代理模式。 代理模式 定义 是结构型设计模式&#xff0c;引入一个对象控制对另…