当前位置: 首页 > article >正文

策略模式 Strategy Pattern

A Beginner's Guide to the Strategy Design Pattern

https://en.wikipedia.org/wiki/Strategy_pattern

Strategy Design Pattern - GeeksforGeeks

介绍

策略模式「strategy pattern 」(也称为policy pattern)是一种行为软件设计模式「behavioral software design pattern 」,可以在运行时选择算法。代码不是直接实现单个算法,而是接收运行时指令,指示使用一系列算法「a family of algorithms」中的哪一个。

在上面的UML类图中,

Context类不直接实现算法。相反,Context引用 用于执行算法的Strategy接口(Strategy.algorithm()),这使得Context独立于算法的实现方式。Strategy1和Strategy2类实现了Strategy接口,即实现(封装)一个算法。

UML序列图显示了运行时交互:

Context对象将算法委托给不同的Strategy对象。首先,Context对Strategy1对象调用algorithm(),该对象执行算法并将结果返回给Context。此后,Context更改其策略,并在Strategy2对象上调用algorithm(),该对象执行算法并将结果返回给Context。

Strategy and open/closed principle

根据策略模式,类的行为不应该被继承。相反,它们应该使用接口封装。这与开放/封闭原则(OCP)是兼容的,OCP建议类应该对扩展开放,但对修改关闭。

例如,考虑一个汽车类。汽车的两种可能的功能是刹车「brake」和加速「accelerate」。由于加速和制动行为在模型之间经常发生变化,一种常见的方法是在子类中实现这些行为。这种方法有明显的缺点;每一款新车都必须声明加速和制动行为。随着模型数量的增加,管理这些行为的工作也会大大增加,并且需要在模型之间复制代码。此外,如果不调查每个模型中的代码,就不容易确定每个模型的行为的确切性质。

策略模式使用组合而不是继承。在策略模式中,行为被定义为单独的接口和实现这些接口的特定类。这允许行为和使用该行为的类之间更好地解耦。可以在不破坏使用它的类的情况下更改行为,并且类可以通过更改所使用的特定实现在行为之间切换,而无需进行任何重大的代码更改。行为也可以在运行时和设计时更改。例如,一个汽车对象的制动行为可以从BrakeWithABS()改变为Brake()通过改变brakeBehavior成员:

brakeBehavior = new Brake();
/* Encapsulated family of Algorithms
 * Interface and its implementations
 */
public interface IBrakeBehavior {
    public void brake();
}

public class BrakeWithABS implements IBrakeBehavior {
    public void brake() {
        System.out.println("Brake with ABS applied");
    }
}

public class Brake implements IBrakeBehavior {
    public void brake() {
        System.out.println("Simple Brake applied");
    }
}

/* Client that can use the algorithms above interchangeably */
public abstract class Car {
    private IBrakeBehavior brakeBehavior;

    public Car(IBrakeBehavior brakeBehavior) {
      this.brakeBehavior = brakeBehavior;
    }

    public void applyBrake() {
        brakeBehavior.brake();
    }

    public void setBrakeBehavior(IBrakeBehavior brakeType) {
        this.brakeBehavior = brakeType;
    }
}

/* Client 1 uses one algorithm (Brake) in the constructor */
public class Sedan extends Car {
    public Sedan() {
        super(new Brake());
    }
}

/* Client 2 uses another algorithm (BrakeWithABS) in the constructor */
public class SUV extends Car {
    public SUV() {
        super(new BrakeWithABS());
    }
}

/* Using the Car example */
public class CarExample {
    public static void main(final String[] arguments) {
        Car sedanCar = new Sedan();
        sedanCar.applyBrake();  // This will invoke class "Brake"

        Car suvCar = new SUV();
        suvCar.applyBrake();    // This will invoke class "BrakeWithABS"

        // set brake behavior dynamically
        suvCar.setBrakeBehavior( new Brake() );
        suvCar.applyBrake();    // This will invoke class "Brake"
    }
}

使用策略模式的对比

package withoutstrategy;

public class PaymentProcessor {
    private PaymentType paymentType;

    public void processPayment(double amount) {
        if (paymentType == PaymentType.CREDIT_CARD) {
            System.out.println("Processing credit card payment of amount " + amount);
        } else if (paymentType == PaymentType.DEBIT_CARD) {
            System.out.println("Processing debit card payment of amount " + amount);
        } else if (paymentType == PaymentType.PAYPAL) {
            System.out.println("Processing PayPal payment of amount " + amount);
        } else {
            throw new IllegalArgumentException("Invalid payment type");
        }
    }

    public void setPaymentType(PaymentType paymentType) {
        this.paymentType = paymentType;
    }
}

enum PaymentType {
    CREDIT_CARD,
    DEBIT_CARD,
    PAYPAL
}
package withstrategy;

public interface PaymentStrategy {
    void processPayment(double amount);
}


public class CreditCardPaymentStrategy implements PaymentStrategy {
    public void processPayment(double amount) {
        System.out.println("Processing credit card payment of amount " + amount);
    }
}

public class DebitCardPaymentStrategy implements PaymentStrategy {
    public void processPayment(double amount) {
        System.out.println("Processing debit card payment of amount " + amount);
    }
}

public class PaypalPaymentStrategy implements PaymentStrategy {
    public void processPayment(double amount) {
        System.out.println("Processing PayPal payment of amount " + amount);
    }
}

public class PaymentProcessor {
    private PaymentStrategy paymentStrategy;

    public PaymentProcessor(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

    public void processPayment(double amount) {
        paymentStrategy.processPayment(amount);
    }
}

实施战略设计模式的最佳实践

保持界面简洁,专注于单一职责。
将任何有状态的行为封装在具体的策略类中,而不是context 类中。
使用依赖注入将具体策略传递给 context 类,而不是直接在context 中创建它。
使用枚举或工厂类为创建和管理具体的策略对象提供一个集中的位置。

战略设计模式的用例

排序算法:不同的排序算法可以封装到单独的策略中,并传递给需要排序的对象。
验证规则:不同的验证规则可以封装到单独的策略中,并传递给需要验证的对象。
文本格式化:不同的格式化策略可以封装到单独的策略中,并传递给需要格式化的对象。
数据库访问:不同的数据库访问策略可以封装到单独的策略中,并传递给需要访问不同来源数据的对象。
支付策略:不同的支付方式可以封装到单独的策略中,并传递给需要处理支付的对象。

排序算法例子

// SortingContext.java
class SortingContext {
    private SortingStrategy sortingStrategy;

    public SortingContext(SortingStrategy sortingStrategy) {
        this.sortingStrategy = sortingStrategy;
    }

    public void setSortingStrategy(SortingStrategy sortingStrategy) {
        this.sortingStrategy = sortingStrategy;
    }

    public void performSort(int[] array) {
        sortingStrategy.sort(array);
    }
}

// SortingStrategy.java
interface SortingStrategy {
    void sort(int[] array);
}

// BubbleSortStrategy.java
class BubbleSortStrategy implements SortingStrategy {
    @Override
    public void sort(int[] array) {
        // Implement Bubble Sort algorithm
        System.out.println("Sorting using Bubble Sort");
        // Actual Bubble Sort Logic here
    }
}

// MergeSortStrategy.java
class MergeSortStrategy implements SortingStrategy {
    @Override
    public void sort(int[] array) {
        // Implement Merge Sort algorithm
        System.out.println("Sorting using Merge Sort");
        // Actual Merge Sort Logic here
    }
}

// QuickSortStrategy.java
class QuickSortStrategy implements SortingStrategy {
    @Override
    public void sort(int[] array) {
        // Implement Quick Sort algorithm
        System.out.println("Sorting using Quick Sort");
        // Actual Quick Sort Logic here
    }
}

// Client.java
public class Client {
    public static void main(String[] args) {
        // Create SortingContext with BubbleSortStrategy
        SortingContext sortingContext = new SortingContext(new BubbleSortStrategy());
        int[] array1 = {5, 2, 9, 1, 5};
        sortingContext.performSort(array1); // Output: Sorting using Bubble Sort

        // Change strategy to MergeSortStrategy
        sortingContext.setSortingStrategy(new MergeSortStrategy());
        int[] array2 = {8, 3, 7, 4, 2};
        sortingContext.performSort(array2); // Output: Sorting using Merge Sort

        // Change strategy to QuickSortStrategy
        sortingContext.setSortingStrategy(new QuickSortStrategy());
        int[] array3 = {6, 1, 3, 9, 5};
        sortingContext.performSort(array3); // Output: Sorting using Quick Sort
    }
}

http://www.kler.cn/a/551785.html

相关文章:

  • 认识HTML的标签结构
  • Uboot编译出现:Makefile:40: *** missing separator. Stop.
  • apache artemis安装
  • H3CNE构建中小企业网络(上)面向零基础
  • AIGC(生成式AI)试用 21 -- Python调用deepseek API
  • Linux 文件内容查看
  • Docker 安全基础:权限、用户、隔离机制
  • http状态码503之解决方法(Solution to HTTP Status Code 503)
  • 部署k8s 集群1.26.0(containerd方式)
  • AI 百炼成神:线性回归,预测房价
  • docker的mysql容器修改数据库root的登录密码后,navicat依然能用旧密码访问
  • Java 设计模式总结
  • Leetcode1299:将每个元素替换为右侧最大元素
  • 半遮挡检测算法 Detecting Binocular Half-Occlusions
  • rust笔记1-学习资料推荐
  • CHARMM-GUI EnzyDocker: 一个基于网络的用于酶中多个反应状态的蛋白质 - 配体对接的计算平台
  • Ubuntu下mysql主从复制搭建
  • three.js+WebGL踩坑经验合集(8.2):z-fighting叠面问题和camera.near的坑爹关系
  • 【系列教程】Python第三课:用前两课知识解决实际问题
  • ES8中 async 和await的用法详细的总结