策略模式 详解 设计模式

策略模式

策略模式是一种行为型设计模式,它定义了一系列算法,将每个算法封装到具有共同接口的独立类中,并且使它们可以相互替换。 策略模式可以让算法的变化独立于使用算法的客户端。

主要解决: 在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护。

结构

策略模式的主要角色如下:

  • 抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。所有具体策略类都实现了该接口。
  • 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
  • 环境/上下文(Context)类:持有一个策略类的引用,负责将客户端的请求委派给具体的策略对象。

图例:

在 Java 中使用策略模式的写法:

  1. 定义策略接口 :创建一个接口,用于定义所有具体策略类的公共行为。
  2. 创建具体策略类:实现策略接口,并提供具体的算法实现。
  3. 创建上下文类:维护一个对策略接口的引用,并提供方法来设置和切换不同的具体策略类。
  4. 客户端使用:在客户端代码中,创建上下文对象,并设置具体的策略类,然后调用上下文对象的方法来执行具体的算法。
java 复制代码
// 1. 定义策略接口
interface PaymentStrategy { 
    void pay(double amount);
}

// 2. 创建具体策略类
class AliPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " via AliPay.");
    }
}

class WeChatPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " via WeChatPay.");
    }
}

// 3. 创建上下文类
class PaymentContext {
    private PaymentStrategy paymentStrategy;

    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

    public void makePayment(double amount) {
        paymentStrategy.pay(amount);
    }
}

// 4. 客户端使用
public class Main {
    public static void main(String[] args) {
        PaymentContext paymentContext = new PaymentContext();

        // 使用支付宝支付
        paymentContext.setPaymentStrategy(new AliPayStrategy());
        paymentContext.makePayment(100.0);

        // 使用微信支付
        paymentContext.setPaymentStrategy(new WeChatPayStrategy());
        paymentContext.makePayment(50.0);
    }
}

代码中创建了策略接口 PaymentStrategy 和两个具体策略类 AliPayStrategy 和 WeChatPayStrategy。然后,创建了上下文类 PaymentContext,它维护了一个对策略接口的引用,并提供了设置和执行具体策略的方法。最后,在客户端 Main 类中,创建了 PaymentContext 的实例,并设置了具体的支付策略,然后进行支付操作。

使用场景:

  • 当有多个相关的类只有行为或算法上稍有不同的情况下,可以考虑使用策略模式。它将算法的变化独立封装到各自的策略类中,易于扩展和维护。

  • 一个系统需要动态地在几种算法中选择一种时,可以将这些行为封装成不同的策略类,并在需要时动态切换。

  • 系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。

  • 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现 ,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。

注意事项: 如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。

混合模式 是指在策略模式中引入了简单工厂模式或者享元模式等其他设计模式,来减少策略类的数量,简化系统的结构。

举例来说,假设一个系统有多种支付方式,除了支付宝支付和微信支付之外,还有银行卡支付、信用卡支付等多种支付方式。如果每种支付方式都对应一个具体的策略类,随着支付方式的增加,策略类的数量会急剧增加,导致类膨胀问题。为了解决这个问题,可以引入简单工厂模式,将支付方式的创建交给一个工厂类来完成;同时,如果某些支付方式具有相似的功能,可以使用享元模式来共享相同的部分,减少策略对象的数量。

代码案例:

java 复制代码
// 1. 定义策略接口
interface PaymentStrategy { 
    void pay(double amount);
}

// 2. 创建具体策略类
class AliPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " via AliPay.");
    }
}

class WeChatPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " via WeChatPay.");
    }
}

class BankCardPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " via BankCard.");
    }
}

class CreditCardPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " via CreditCard.");
    }
}

// 3. 创建简单工厂类
class PaymentStrategyFactory {
    private static final Map<String, PaymentStrategy> strategies = new HashMap<>();

    static {
        strategies.put("AliPay", new AliPayStrategy());
        strategies.put("WeChatPay", new WeChatPayStrategy());
        // 可以添加更多支付方式的策略对象
    }

    public static PaymentStrategy getPaymentStrategy(String type) {
        return strategies.get(type);
    }
}

// 4. 客户端使用
public class Main {
    public static void main(String[] args) {
        PaymentStrategy aliPayStrategy = PaymentStrategyFactory.getPaymentStrategy("AliPay");
        aliPayStrategy.pay(100.0);

        PaymentStrategy weChatPayStrategy = PaymentStrategyFactory.getPaymentStrategy("WeChatPay");
        weChatPayStrategy.pay(50.0);

        PaymentStrategy bankCardPayStrategy = PaymentStrategyFactory.getPaymentStrategy("BankCard");
        bankCardPayStrategy.pay(80.0);

        PaymentStrategy creditCardPayStrategy = PaymentStrategyFactory.getPaymentStrategy("CreditCard");
        creditCardPayStrategy.pay(120.0);
    }
}
相关推荐
蛋蛋的就会顺顺的6 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
需要8267 小时前
Spring Bean 生命周期:从实例化到销毁的完整钩子
java·后端·spring
小 黄 鸡7 小时前
HashMap 面试必会知识点详解(JDK 8)
java·面试·职场和发展
死磕音视频8 小时前
让小模型做选择题:限定候选项并读取 logits 概率的入门实践(附 Python 代码)
开发语言·python·大模型·文本分类·transformers
伯恩bourne9 小时前
Spring Boot Bean 注册的两种方式:@Component 家族 vs @Configuration + @Bean
java·spring boot·后端
silvamux_9 小时前
curl 测试 OpenAI 兼容 API 的完整流程
java·人工智能·缓存·ai·oneapi
省钱兄--zs10 小时前
深圳24小时自助健身房软硬件解决方案实战指南与开发流程详解
java·数据仓库·spring boot·小程序·架构
顽疲10 小时前
Java vue 养老系统源码详解:月账单 care_month_bill 与 Quartz 扣费 Job 实践
java·开发语言·vue.js·vue养老·springboot养老·java养老
Wang's Blog10 小时前
Java 项目实战: 交友项目 - 安装开发工具与环境准备
java·开发语言·交友
用户212968352616810 小时前
开源了一个 Java 多智能体 LLM 框架 Baton:一个依赖,把 Agent 循环、工具调用、记忆、编排全配齐
java·llm