使用策略模式


引言

在软件和网站开发中,编写可维护和可扩展的代码总是非常重要的。你首次创建的解决方案可能会随着时间的推移而变化。因此,你需要确保以一种方式来编写代码,以免在未来需要完全重写或重构。

策略模式可以用来提高你代码的可扩展性,也可以提高随着时间的推移而对代码的可维护性。

目标读者

本篇教程可能是此指南中最复杂的一部分。它是为了了解接口如何工作以及如何使用它们来解耦代码的 Laravel 开发者所写的。如果你已经读过上一篇教程,你应该能够理解整体的概念。在我个人看来,理解本篇教程涵盖的概念的最好方法是在读这一篇教程的时候(或者你已经阅读完毕的时候)自己去试试。

强烈建议你有对依赖注入和 Laravel 服务容器如何工作的理解。如果你不了解,可以参考这篇教程以及 Laravel 从学徒到工匠系列教程。

什么是策略模式?

重构大师将策略模式定义为一个"让你定义一家算法,将它们每一个放入一个独立的类,并让它们的对象可以互换的行为设计模式"。这在一开始听起来可能会有点可怕,但我保证它并不像你想象的那样糟糕。如果你想更深入地了解设计模式,我强烈推荐你去看看重构大师。他们非常棒地解释了策略模式以及其他结构模式的深度。

策略模式基本上是一个帮助我们解耦代码并使其超级可扩展的模式。

在 Laravel 中使用策略模式

既然我们对策略模式有了基本概念,我们来看看在我们自己的 Laravel 应用程序中如何使用它。假设我们有一个 Laravel 应用,用户可以使用它来获取汇率和货币兑换。现在,假设我们的应用使用外部 API (exchangeratesapi.io)获取最新的货币兑换。我们可以创建一个类来与 API 交互:

image-20230831170752444

然后,我们在控制器方法中使用这个类,返回给定货币的汇率。我们将使用依赖注入来从容器中解析这个类:

image-20230831170806941

此代码将按预期工作,但我们已经将 ExchangeRatesApiIO 类紧密地耦合到控制器方法中。这意味着如果我们决定未来转向使用不同的 API,比如 Fixer,我们需要将代码库中使用 ExchangeRatesApiIO 类的所有地方替换为我们的新类。如你所想,大型项目中这可能是一个慢而乏味的任务。因此,要避免这个问题,我们可以使用策略模式来绑定和解析接口,而不是在控制器中尝试实例化类。

首先,让我们创建一个新的 ExchangeRatesService 接口:

image-20230831170843799

我们现在可以更新我们的 ExchangeRatesApiIO 类来实现这个接口:

image-20230831170855058

现在我们已经完成了这一步,我们可以更新我们的控制器方法来注入接口而不是类:

image-20230831170903093

当然,我们不能实例化一个接口;我们需要实例化 ExchangeRatesApiIO 类。所以,我们需要告诉 Laravel 在我们尝试解析容器中的接口时做什么。我们可以通过使用服务提供者来做到这一点。有些人喜欢将这些东西放在他们的 AppServiceProvider 中,并将所有的绑定都放在一个地方。然而,我更喜欢为我想建立的每一个绑定创建一个独立的提供者。这完全取决于个人偏好和你认为适合你的工作流程。在这个例子中,我们将创建我们自己的服务提供者。

使用 Artisan 命令创建新的服务提供者:

php artisan make:provider ExchangeRatesServiceProvider

然后我们需要记住在 app/config.php 中注册这个服务提供者,如下所示:

image-20230831171001297

现在,我们可以将我们的代码添加到服务提供者中来绑定接口和类:

image-20230831171007654

完成所有这些步骤后,当我们在控制器方法中注入 ExchangeRatesService 接口,我们将会得到一个我们可以使用的 ExchangeRatesApiIO 类。

将多个类绑定到接口

现在我们知道如何将一个接口绑定到一个类,让我们深入一步。假设我们想要决定是否使用ExchangeRatesAPI.io 还是 Fixer.io API,只需通过更新配置字段即可。

我们还没有一个类来处理 Fixer.io API,所以让我们创建一个,并确保它实现 ExchangeRatesService 接口:

image-20230831171434868

我们现在在我们的 config/services.php 文件中创建一个新的字段:

image-20230831171446390

我们现在可以更新我们的服务提供者来改变我们从容器中解析接口时将返回哪个类:

image-20230831171501352

设置我们的交易汇率驱动在我们的 .envEXCHANGE_RATES_DRIVER=exchangeratesapiio 并尝试解析容器中的ExchangeRatesService,我们会得到一个 ExchangeRatesApiIO 类。如果我们在 .env 中设置EXCHANGE_RATES_DRIVER=fixerio 并尝试解析容器中的 ExchangeRatesService,我们会得到 FixerIO 类。如果我们忽然将驱动设置为其他任何东西,会抛出一个异常,让我们知道设置不正确。

由于这两个类都实现了相同的接口,我们可以无缝地更改在 .env 中的 EXCHANGE_RATES_DRIVER 字段,而不需要改变任何其他代码。

小结

你的大脑已经炸了吗?如果是,请别担心!我第一次学习这个主题的时候也觉得挺难的。我认为直到我放到实践中,自己使用它,我才真正开始理解它。因此,我建议你花一点时间自己尝试这个。一旦你对使用它感到舒服,我保证你会在你自己的项目中使用它。

本篇教程为你提供了关于策略模式是什么以及你在 Laravel 中如何使用它来提高代码的可扩展性和可维护性的概述。


点赞 取消点赞 收藏 取消收藏

<< 上一篇: 面向接口编程

>> 下一篇: 编写可测试代码