23种设计模式之策略模式

文章目录

    • 策略模式
    • 策略模式的结构
    • [策略模式 - 支付案例 - Java实现](#策略模式 - 支付案例 - Java实现)
    • [策略模式 - 支付案例 - Spring依赖注入方式实现](#策略模式 - 支付案例 - Spring依赖注入方式实现)
    • 总结

策略模式

策略模式是一种行为型设计模式,其核心在于定义了一系列算法,并将各个算法分别进行封装,使得这些算法能够相互替换。通过这种方式,策略模式实现了算法的变化独立于使用算法的客户,极大地增强了系统的灵活性和可维护性。

在实际开发过程中,策略模式常常被用于优化存在大量分支判断的代码。它能够将复杂的条件逻辑转化为不同的策略对象,避免了冗长的分支语句,使代码更加清晰、易读和易于扩展。当需要新增一种算法时,只需创建一个新的策略类并实现相应的接口,而无需修改现有的代码逻辑,完全符合开闭原则。

策略模式的结构

一、结构组成
环境类(Context):持有一个策略对象的引用,最终给客户端调用的入口。环境类在运行时会根据具体情况选择不同的策略对象来完成特定的任务。例如,一个购物系统中的结算模块可以作为环境类,根据不同的促销活动选择不同的折扣策略。

抽象策略类(Strategy) :定义了所有支持算法的公共接口。具体的策略实现类都要实现这个接口,确保它们具有相同的方法签名,以便在环境类中可以无缝切换。比如,定义一个计算折扣的抽象方法。

具体策略类(ConcreteStrategy):实现了抽象策略类中的具体算法。可以有多个具体策略类,每个代表一种不同的具体策略。例如,不同的折扣策略类,如满减折扣策略、固定折扣率策略等。

二、优点

**开闭原则:**可以在不修改原有代码的基础上,轻松添加新的策略。当需要引入新的算法或行为时,只需要创建一个新的具体策略类并实现抽象策略接口,而不会影响到现有的代码结构。

代码复用:多个环境类可以共享同一个策略类,避免了代码重复。例如,不同的业务模块如果都需要进行某种类型的计算,就可以复用相同的策略类。

易于切换算法:由于策略的实现与使用分离,在运行时可以根据不同的条件动态地切换策略。这使得系统具有更好的灵活性和可维护性。

三、缺点

**策略类数量增多:**随着系统中策略的增加,会导致类的数量增多,可能会使系统变得复杂。

客户端必须了解策略的区别:客户端需要了解不同策略之间的差异,以便选择合适的策略。这增加了客户端的复杂性和认知负担。

四、使用场景

**多个算法变体:**当一个系统中存在多种相似的算法变体时,可以使用策略模式将这些算法封装起来,以便在不同的情况下进行切换。例如,在一个图像编辑软件中,可以有不同的图像滤镜算法,用户可以根据需要选择不同的滤镜。

**业务规则的变化:**当业务规则经常变化时,使用策略模式可以将不同的业务规则封装成不同的策略类,方便在运行时进行切换。比如,在一个物流系统中,根据不同的运输方式和距离计算运费的规则可能会经常变化,可以使用策略模式来实现不同的运费计算策略。

避免条件语句的复杂嵌套:如果一个系统中存在大量的条件语句来选择不同的算法,会使代码变得难以维护。使用策略模式可以将这些条件语句转化为不同的策略类,使代码更加清晰易读。

策略模式 - 支付案例 - Java实现

以下是使用不同支付方式的策略模式示例:

一、定义支付策略接口

java 复制代码
public interface PaymentStrategy {
    void pay(double amount);
}

二、创建具体支付策略类

java 复制代码
public class WeChatPaymentStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("使用微信支付:" + amount + "元。");
    }
}

public class AlipayPaymentStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("使用支付宝支付:" + amount + "元。");
    }
}

public class UnionPayPaymentStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("使用银联支付:" + amount + "元。");
    }
}

public class PayPalPaymentStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("使用 PayPal 支付:" + amount + "元。");
    }
}

三、创建支付上下文类

java 复制代码
public class PaymentContext {
    private PaymentStrategy paymentStrategy;

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

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

四、使用示例

下面测试使用四种不同的方式支付。

java 复制代码
public class StrategyTest {
    public static void main(String[] args) {
        double amount = 100.0;
        // 下面测试使用四种不同的方式支付,使用PaymentContext的参数指定支付方式。
        PaymentContext weChatPayment = new PaymentContext(new WeChatPaymentStrategy());
        weChatPayment.makePayment(amount);

        PaymentContext alipayPayment = new PaymentContext(new AlipayPaymentStrategy());
        alipayPayment.makePayment(amount);

        PaymentContext unionPayPayment = new PaymentContext(new UnionPayPaymentStrategy());
        unionPayPayment.makePayment(amount);

        PaymentContext paypalPayment = new PaymentContext(new PayPalPaymentStrategy());
        paypalPayment.makePayment(amount);
    }
}

运行测试代码,结果如下。

bash 复制代码
使用微信支付:100.0元。
使用支付宝支付:100.0元。
使用银联支付:100.0元。
使用 PayPal 支付:100.0元。

策略模式 - 支付案例 - Spring依赖注入方式实现

在 Spring 中存在 IOC(控制反转)容器,这使得策略模式的运用能够更加灵活。IOC 容器可以方便地管理不同的策略实现类,通过配置文件或注解等方式实现策略的动态注入和切换,极大地增强了系统的可扩展性和可维护性。

下面我在SpringBoot项目中使用。对上面的支付案例进行改造。

一、首先对策略实现类交给IOC容器

PaymentStrategy 接口还是使用的java实现版的接口。

java 复制代码
@Service("WECHATPAY")
public class WeChatPaymentStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("使用微信支付:" + amount + "元。");
    }
}

@Service("ALIPAY")
public class AlipayPaymentStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("使用支付宝支付:" + amount + "元。");
    }
}

@Service("UNIONPAY")
public class UnionPayPaymentStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("使用银联支付:" + amount + "元。");
    }
}

@Service("PAYPALPAY")
public class PayPalPaymentStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("使用 PayPal 支付:" + amount + "元。");
    }
}

二、创建支付服务

下面的支付服务不是线程安全的,只是一个支付策略的demo。

java 复制代码
@Service
public class PaymentService {
    private PaymentStrategy paymentStrategy;
	// 调用支付接口
    public void pay(double amount) {
        paymentStrategy.pay(amount);
    }
	// 设置支付方式
    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

}

三、使用测试

下面写了四个支付测试方法,分别测试不同的支付方法。

java 复制代码
@SpringBootTest
public class PaymentServiceTest {
    @Resource
    private PaymentService paymentService;

    @Test
    public void testAliPay() {
        System.out.println("testAliPay");
        // 下面的支付金额和支付方式当做前端传过来的参数
        double amount = 100.0;
        String payMethod = "ALIPAY";
        // 设置支付方式
        // 获取支付策略类,使用Hutool工具
        PaymentStrategy paymentStrategy = SpringUtil.getBean(payMethod, PaymentStrategy.class);
        // 设置支付策略
        paymentService.setPaymentStrategy(paymentStrategy);
        // 支付
        paymentService.pay(amount);
        System.out.println("--------------------");
    }

    @Test
    public void testPayPal() {
        System.out.println("testPayPal");
        double amount = 100.0;
        String payMethod = "PAYPALPAY";
        PaymentStrategy paymentStrategy = SpringUtil.getBean(payMethod, PaymentStrategy.class);
        paymentService.setPaymentStrategy(paymentStrategy);
        paymentService.pay(amount);
        System.out.println("--------------------");
    }

    @Test
    public void testUnionPay() {
        System.out.println("testUnionPay");
        double amount = 100.0;
        String payMethod = "UNIONPAY";
        PaymentStrategy paymentStrategy = SpringUtil.getBean(payMethod, PaymentStrategy.class);
        paymentService.setPaymentStrategy(paymentStrategy);
        paymentService.pay(amount);
        System.out.println("--------------------");
    }

    @Test
    public void testWechatPay() {
        System.out.println("testWechatPay");
        double amount = 100.0;
        String payMethod = "WECHATPAY";
        PaymentStrategy paymentStrategy = SpringUtil.getBean(payMethod, PaymentStrategy.class);
        paymentService.setPaymentStrategy(paymentStrategy);
        paymentService.pay(amount);
        System.out.println("--------------------");
    }
}

测试结果:

java 复制代码
testUnionPay
使用银联支付:100.0元。
--------------------
testWechatPay
使用微信支付:100.0元。
--------------------
testAliPay
使用支付宝支付:100.0元。
--------------------
testPayPal
使用 PayPal 支付:100.0元。
--------------------

总结

一、策略模式的结构

策略模式主要由三部分组成:环境类(Context)、抽象策略类(Strategy)和具体策略类(ConcreteStrategy)。环境类持有一个策略对象的引用,通过设置不同的策略对象,可以在运行时动态地切换算法。抽象策略类定义了算法的公共接口,具体策略类则实现了这些接口,代表不同的具体算法。

二、策略模式的支付案例 Java 实现

通过使用不同的支付方式(如微信支付、支付宝支付、银联支付、PayPal 支付等)作为具体策略,展示了策略模式在实际应用中的强大之处。在 Java 实现中,定义了支付策略接口PaymentStrategy,各个具体支付策略类实现该接口,如WeChatPaymentStrategyAlipayPaymentStrategy等。同时,创建支付上下文类PaymentContext,用于在运行时根据不同的策略进行支付操作。

三、策略模式的支付案例 Spring 依赖注入方式实现

借助 Spring 的依赖注入功能,可以更加灵活地管理和切换支付策略。在PaymentService类中,通过设置支付策略的方法setPaymentStrategy,可以在运行时动态地注入不同的支付策略。这种方式使得代码更加简洁、易于维护,并且可以充分利用 Spring 的强大功能,如自动装配、生命周期管理等。

总之,策略模式为我们提供了一种优雅的方式来处理算法的变化和多样化。无论是在简单的应用场景还是复杂的企业级系统中,策略模式都能发挥重要作用,提高代码的可维护性、可扩展性和灵活性。

相关推荐
qq_433618441 小时前
shell 编程(二)
开发语言·bash·shell
weixin_437398211 小时前
Linux扩展——shell编程
linux·运维·服务器·bash
大圣数据星球5 小时前
Fluss 写入数据湖实战
大数据·设计模式·flink
思忖小下6 小时前
梳理你的思路(从OOP到架构设计)_设计模式Template Method模式
设计模式·模板方法模式·eit
yylの博客16 小时前
Windows通过git-bash安装zsh
windows·git·bash·zsh
思忖小下16 小时前
梳理你的思路(从OOP到架构设计)_简介设计模式
设计模式·架构·eit
liyinuo201718 小时前
嵌入式(单片机方向)面试题总结
嵌入式硬件·设计模式·面试·设计规范
aaasssdddd9620 小时前
C++的封装(十四):《设计模式》这本书
数据结构·c++·设计模式
T1an-120 小时前
设计模式之【观察者模式】
观察者模式·设计模式
思忖小下1 天前
梳理你的思路(从OOP到架构设计)_设计模式Factory Method模式
设计模式·工厂方法模式·eit