目录
策略模式:软件开发的 “瑞士军刀”
在软件开发的广阔领域中,我们常常会遇到这样的情况:解决同一个问题存在多种方法,而且在不同的场景下,需要动态地选择最合适的方法。这就好比我们出行时,根据距离、时间、预算等因素,会选择不同的交通工具,如步行、骑自行车、坐公交、乘地铁或者开车。在编程世界里,策略模式就扮演着这样一个智能的 “出行规划师” 角色,它为我们提供了一种优雅而灵活的方式来处理多种算法和行为。
想象一下,你正在开发一个电商系统,其中的订单支付功能需要支持多种支付方式,如信用卡支付、支付宝支付、微信支付等。如果不使用任何设计模式,你可能会写出一个包含大量if - else语句的方法来处理不同的支付逻辑:
public class PaymentService {
public void pay(String paymentType, double amount) {
if ("creditCard".equals(paymentType)) {
// 信用卡支付逻辑
System.out.println("使用信用卡支付:" + amount);
} else if ("alipay".equals(paymentType)) {
// 支付宝支付逻辑
System.out.println("使用支付宝支付:" + amount);
} else if ("wechatPay".equals(paymentType)) {
// 微信支付逻辑
System.out.println("使用微信支付:" + amount);
} else {
System.out.println("不支持的支付方式");
}
}
}
这样的代码虽然能实现基本功能,但存在诸多问题。首先,代码的可维护性差,如果要新增一种支付方式,就需要在这个if - else语句块中添加新的条件分支,这不仅增加了代码的复杂度,还容易引入错误。其次,代码的扩展性也不好,每次修改支付逻辑都需要直接修改这个方法,违反了软件开发中的开闭原则(对扩展开放,对修改关闭)。
那么,策略模式是如何解决这些问题的呢?策略模式的核心思想是将不同的算法或行为封装成独立的策略类,这些策略类实现同一个策略接口,使得它们可以相互替换。在上面的支付场景中,我们可以定义一个支付策略接口PaymentStrategy,然后为每种支付方式创建一个具体的策略类来实现这个接口:
// 支付策略接口
public interface PaymentStrategy {
void pay(double amount);
}
// 信用卡支付策略类
public class CreditCardPaymentStrategy 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 WechatPayPaymentStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("使用微信支付:" + amount);
}
}
接下来,我们创建一个支付上下文类PaymentContext,它持有一个支付策略的引用,并提供一个方法来执行支付操作:
public class PaymentContext {
private PaymentStrategy paymentStrategy;
public PaymentContext(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void executePayment(double amount) {
paymentStrategy.pay(amount);
}
}
在客户端代码中,我们可以根据需要动态地选择不同的支付策略:
public class Client {
public static void main(String[] args) {
// 使用信用卡支付
PaymentContext creditCardContext = new PaymentContext(new CreditCardPaymentStrategy());
creditCardContext.executePayment(100.0);
// 使用支付宝支付
PaymentContext alipayContext = new PaymentContext(new AlipayPaymentStrategy());
alipayContext.executePayment(200.0);
// 使用微信支付
PaymentContext wechatPayContext = new PaymentContext(new WechatPayPaymentStrategy());
wechatPayContext.executePayment(300.0);
}
}
通过策略模式,我们将支付逻辑的实现与使用分离,每个支付策略类只负责自己的支付逻辑,使得代码更加清晰、可维护和可扩展。当需要新增支付方式时,只需创建一个新的策略类实现PaymentStrategy接口,而无需修改现有的代码,这正是策略模式的魅力所在。
一、什么是策略模式
(一)定义与概念
策略模式(Strategy Pattern)是一种行为型设计模式,其定义为:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。该模式使得算法可以独立于使用它的客户端而变化 。简单来说,策略模式将不同的算法封装成独立的类,这些类实现同一个接口,客户端可以根据不同的场景选择不同的算法类来执行相应的操作。这种模式就像是为程序准备了一套 “算法工具箱”,在需要的时候可以灵活地选择和切换工具,而不影响程序的其他部分。
(二)策略模式的角色
- 抽象策略(Strategy)
抽象策略角色是一个接口或抽象类,它定义了一个或多个方法,这些方法代表了一系列相关的算法或行为。所有的具体策略类都必须实现这个接口或继承这个抽象类,以提供具体的算法实现。在我们前面提到的支付系统中,支付策略接口PaymentStrategy就是抽象策略角色:
public interface PaymentStrategy {
void pay(double amount);
}
这个接口定义了一个pay方法,用于执行支付操作,具体的支付逻辑由实现该接口的具体策略类来完成。通过定义这样的抽象策略,我们可以将支付行为抽象出来,使得不同的支付方式可以通过实现该接口来提供自己的支付实现,从而实现算法的可替换性。
具体策略(Concrete Strategy)
具体策略类是实现了抽象策略接口的具体类,每个具体策略类封装了一种具体的算法或行为。在支付系统中,CreditCardPaymentStrategy、AlipayPaymentStrategy和WechatPayPaymentStrategy就是具体策略类:
// 信用卡支付策略类
public class CreditCardPaymentStrategy 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);
// 这里可以添加实际的支付宝支付逻辑,如调用支付宝SDK进行支付操作等
}
}
// 微信支付策略类
public class WechatPayPaymentStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("使用微信支付:" + amount);
// 这里可以添加实际的微信支付逻辑,如调用微信支付API进行支付等
}
}
每个具体策略类都实现了PaymentStrategy接口的pay方法,提供了具体的支付实现。这些具体策略类之间相互独立,它们的变化不会影响到其他的策略类和客户端代码,符合单一职责原则和开闭原则。
上下文(Context)
上下文类也称为环境类,它持有一个抽象策略类的引用,并提供一个方法来执行策略对象的方法。上下文类的作用是将客户端与具体的策略类解耦,客户端通过上下文类来调用具体的策略方法,而不需要直接与具体策略类交互。在支付系统中,PaymentContext就是上下文类:
public class PaymentContext {
private PaymentStrategy paymentStrategy;
public PaymentContext(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void executePayment(double amount) {
paymentStrategy.pay(amount);
}
}
PaymentContext类持有一个PaymentStrategy类型的引用paymentStrategy,并通过构造函数进行初始化。executePayment方法调用paymentStrategy的pay方法来执行具体的支付操作。这样,客户端只需要创建PaymentContext对象,并传入相应的具体策略对象,就可以执行支付操作,而不需要了解具体策略类的实现细节。例如:
public class Client {
public static void main(String[] args) {
// 使用信用卡支付
PaymentContext creditCardContext = new PaymentContext(new CreditCardPaymentStrategy());
creditCardContext.executePayment(100.0);
// 使用支付宝支付
PaymentContext alipayContext = new PaymentContext(new AlipayPaymentStrategy());
alipayContext.executePayment(200.0);
// 使用微信支付
PaymentContext wechatPayContext = new PaymentContext(new WechatPayPaymentStrategy());
wechatPayContext.executePayment(300.0);
}
}
在客户端代码中,我们通过创建PaymentContext对象,并传入不同的具体策略对象,实现了不同支付方式的调用,而客户端代码与具体的支付策略实现完全解耦,提高了代码的灵活性和可维护性。