作者丨Ashutosh Krishna
译者丨张哲刚
审校丨重楼
策略设计模式是一种行为设计模式。利用它,你可以通过将对象封装到不同的策略中,进而动态地更改对象的行为。
这种模式可以使对象在运行时能够从多个算法和行为中进行选择,而不限于仅仅静态地选择单个算法和行为。
策略设计模式是基于组合而不是继承的原则。它定义了一系列算法,封装了每个算法,它们在运行时可以互相转换。策略设计模式的核心思想是将算法与主对象分开。它允许对象将算法的行为委托给所设计的众多策略中的一个。
一言而蔽之,策略设计模式提供了一种方法,这种方法可以将对象的行为提取到可以在运行时切换出入的单独类中。从而使对象具有更好的灵活性和重用性,因为这种模式可以轻易地添加或修改不同的策略,而无需更改对象的核心代码。
一、使用策略设计模式的好处
使用策略设计模式有很多便利之处,具体如下:
更好的代码灵活性:通过将对象的行为封装到不同的策略中,使得代码更加灵活且更易于修改。
更好的代码可重用性:由于这些策略是可封装以及可以互换的,所以它们可以在不同的对象和项目中重复使用。
促使更好的编码实践:策略设计模式可以促使良好的编码实践,养成良好的编码习惯,例如关注点分离以及代码复杂性的降低。
简化测试:策略设计模式通过将算法和行为与对象分离,从而使测试得到简化。
二、策略设计模式的实例
策略设计模式可以应用于各种场景,典型的例子如下:
排序算法:可以将不同的排序算法封装到单独的策略中,并发送给需要排序的对象。
验证规则:可以将不同的验证规则封装到单独的策略中,并发送给需要验证的对象。
文本格式:可以将不同的文本格式设置策略封装到单独的策略中,并发送给需要格式化的对象。
数据库访问:可以将不同的数据库访问策略封装到单独的策略中,并发送给需要从不同的数据源访问数据的对象。
支付策略:可以将不同的支付方式封装到单独的策略中,并发送给需要处理支付的对象。
三、了解策略设计模式
策略设计模式是面向对象的编程领域里一个非常卓越的模式。它提供了一种灵活的方法来封装和交换对象在运行时的行为,从而使代码更具适应性且更易于维护。
在本节中,我们将更深入地探讨策略设计模式,研究其定义、组件及其工作原理。
1.策略设计模式的组成部分
策略设计模式主要包括三项重要组件:
- 上下文:策略设计模式所包含的策略行为委托对象。上下文负责维护对策略对象的引用,并通过公共接口与其进行交互。
- 策略接口:此接口定义所有策略的行为。策略通过此接口来实现其定义的各种行为。
- 具体策略:实现策略接口的类。每个策略都封装了一个特定的行为,上下文可以在运行时切换到该行为。
2.策略设计模式的工作原理
策略设计模式的工作原理,是将对象的行为与对象本身分开。行为封装到不同的策略中,每个策略都有自己特定的行为实施。
上下文维护对策略对象的引用,并通过公共接口与其进行交互。在运行进程中,上下文可以将当前策略与另外的策略进行交换,从而有效达到更改对象行为的目的。
3.策略设计模式的实际应用举例
音乐流媒体服务是策略设计模式的一个应用实例。这项服务里,不同的订阅层次有其各自不同的定价模型。
针对每个订阅层次,可以用不同的定价策略来封装其单独的价格体系。该服务的计费系统会将定价计算这一行为事项委托给当前订阅层次对应的策略,从而可以轻松修改和扩展价格体系。
支付策略是另外一个应用实例。不同的支付方式可以封装成单独的策略,每种策略都具有它自身单独的处理逻辑。
购物车应用程序可以使用策略设计模式将信用卡、PayPal和加密货币支付方法封装到单独策略中,它们可以在运行时交换。应用程序的支付处理系统将支付方式委托给当前制定的策略,从而可以轻松修改和扩展支付方式。
四、如何实现策略设计模式
在本节中,我们将讨论如何实现策略设计模式。我们将从一个不符合策略设计模式的代码示例开始,找到和研究它存在的问题。然后,我们再重构代码,来演示如何实现策略设计模式。
要在Java中实现策略设计模式,需要执行以下步骤:
- 确定需要封装的算法或行为,并使其可互换。
- 定义一个表示行为的接口,使用单一方法签名来接收所有必需的参数。
- 实施一个具体类,用来提供接口中所定义行为的特定实现。
- 定义一个上下文类,该上下文类保持对接口的引用并在需要时调用其方法。
- 修改上下文类,以允许动态交换在运行时得以具体实现。
1.代码示例
我们来看以下代码:
packagewithoutstrategy;publicclassPaymentProcessor{
privatePaymentTypepaymentType;
publicvoidprocessPayment(doubleamount){
if(paymentType==PaymentType.CREDIT_CARD){
System.out.println("Processing
credit card payment of amount "+amount);
}elseif(paymentType==PaymentType.DEBIT_CARD){
System.out.println("Processing
debit card payment of amount "+amount);
}elseif(paymentType==PaymentType.PAYPAL){
System.out.println("Processing
PayPal payment of amount "+amount);
}else{
thrownewIllegalArgumentException("Invalid
payment type");
}
}
publicvoidsetPaymentType(PaymentTypepaymentType){
this.paymentType=paymentType;}}enumPaymentType{
CREDIT_CARD,
DEBIT_CARD,
PAYPAL}
支付处理器.java
在此代码中,支付处理器类具有一个用来接受付款金额并处理付款的方法。付款类型是使用“设置付款类型”方法设置并设置“付款类型”字段。然后,该方法检查其值并处理相应的付款。
此代码的问题在于它违反了开-闭(开放封闭)原则,该原则指明类应该面向扩展开放,但必须面向修改封闭。而在此代码中,如果想要添加新的付款类型,则必须修改方法,这就违反了开-闭原则。
该支付处理器类通过使用条件语句来确定付款类型,然后相应地对其进行处理,从而违反了策略模式。随着付款类型数量的增加,这种方法很快就会变得难以管理和不够灵活。
要解决这个问题,可以使用策略设计模式。首先,为所有支付策略定义一个通用接口,在本例中为支付策略接口:
package withstrategy;
public interface PaymentStrategy {
void processPayment(double amount);
}
支付策略.java
然后,你可以为每种付款类型定义其支付策略接口的具体实现。例如下面这些类:
- 信用卡支付策略;
- 借记卡支付策略;
- 贝宝支付策略。
package withstrategy;
public class CreditCardPaymentStrategy implements PaymentStrategy {
public void processPayment(double amount) {
System.out.println("Processing credit card payment of amount " + amount);
}
}
信用卡支付策略.java
package withstrategy;
public class DebitCardPaymentStrategy implements PaymentStrategy {
public void processPayment(double amount) {
System.out.println("Processing debit card payment of amount " + amount);
}
}
借记卡支付策略.java
package withstrategy;
public class PaypalPaymentStrategy implements PaymentStrategy {
public void processPayment(double amount) {
System.out.println("Processing PayPal payment of amount " + amount);
}
}
贝宝支付策略.java
最后,更新支付处理器类用以从构造器中获取支付策略对象,用于处理付款流程:
package withstrategy;
public class PaymentProcessor {
private PaymentStrategy paymentStrategy;
public PaymentProcessor(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void processPayment(double amount) {
paymentStrategy.processPayment(amount);
}
}
支付处理器.java
这一实现遵循开闭原则和策略模式,在其中你可以通过创建支付策略接口的新实现来添加新的支付类型,而并不需要修改现有代码。
2.实施策略设计模式的最佳方案
下面是实施策略设计模式时,要力争记牢的一些最佳方案:
- 保持界面简洁,专注于单一职责。
- 将任何有状态的行为封装在具体策略类中,而不是在上下文类中。
- 使用依赖关系注入将具体策略传达给上下文类,而不是直接在上下文类中创建它。
- 使用枚举或工厂类为创建和管理具体策略对象提供集中位置。
五、策略设计模式的实际应用
策略设计模式已经广泛用于各种实际应用。Java集合框架就是一个鲜明的例子。集合框架提供了一组接口和类来表示对象的集合,例如列表、集和映射。依据集合的具体行为,该框架允许将不同的策略应用于集合。
例如,集合框架包含一个名为“分类”的方法,用于对集合进行排序。该方法将比较器对象作为参数,负责比较集合中的对象。比较器接口定义了用于比较两个对象的策略,“分类”方法使用此策略对集合进行排序。
此外,集合框架还包括迭代器接口,该接口定义了访问集合元素的策略。迭代器允许用户遍历集合,而不会公开其内部结构,该结构可能会随时间而变化。通过使用迭代器接口,用户可以在访问集合元素的不同策略之间切换。
六、总结
在本教程中,我们探讨了策略设计模式及其在Java中的实现。我们已经了解了如何使用策略模式将对象的行为与其实现分开,从而使代码具备更大的灵活性和可维护性。
我们讨论了策略设计模式的组件,包括上下文、策略接口和具体策略。我们还提供了一个示例,用以说明如何使用该模式来实现支付系统的灵活性,可以在单个界面实现多种支付选项。
通过将对象的行为与其实现分离,策略模式提供了足够的灵活性,更能够适应日新月异不断变化的实际需求。
译者介绍:
张哲刚,51CTO社区编辑,系统运维工程师,国内较早一批硬件评测及互联网从业者,曾入职阿里巴巴。
原文链接:https://www.freecodecamp.org/news/a-beginners-guide-to-the-strategy-design-pattern/