策略模式允许在运行时改变对象行为,创建代表不同策略的对象,上下文对象根据所选策略改变执行算法,在电商平台支付系统中,用户可选多种支付方式,每种方式有独特处理流程,策略模式将各支付方式作为策略封装,用户选择时执行相应逻辑,这遵循开闭原则,增强系统可扩展性和可维护性。
定义
策略模式(Strategy Pattern)是行为设计模式之一,它能在运行时改变对象的行为,在策略模式中,一个类的行为或其算法可以在运行时更改,这种类型的设计模式属于行为模式,在策略模式中,需要创建表示各种策略的对象,和一个行为随着策略对象改变而改变的上下文对象,策略对象会改变上下文对象的执行算法。
举一个业务中的实际例子,假设正在开发一个电商平台的支付系统,在这个系统中,用户可以选择多种支付方式,比如支付宝、微信支付、银行卡支付等,每种支付方式都有自己的一套流程和算法,这个场景中可以使用策略模式,可以把每种支付方式看作是一个策略,每个策略都封装了各自支付方式的流程和算法,当用户选择某种支付方式时,只需要在运行时动态地切换到对应的策略即可。
具体来说,可以定义一个支付策略的接口,这个接口中定义了支付方法,然后,为每种支付方式创建一个类,这些类实现了支付策略的接口,并实现了各自的支付方法,最后,创建一个上下文类,这个类中包含一个支付策略的引用,以及一个执行支付的方法,当用户选择支付方式时,只需要在上下文类中设置对应的支付策略,然后调用执行支付的方法即可。
这样的好处是,如果以后需要增加新的支付方式,只需要创建新的策略类,而不需要修改上下文类和其他已有的策略类,这也符合开闭原则,使得系统更加灵活和可扩展。
代码案例
反例
下面是一个未使用策略模式的反例代码,有一个支付系统,它支持支付宝和微信支付,但是支付方式的选择是硬编码在支付处理类中的,而不是通过策略模式动态选择的,如下代码:
// 支付方式接口
public interface PaymentMethod {
void pay(double amount);
}
// 支付宝支付实现
public class Alipay implements PaymentMethod {
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付 " + amount + " 元");
}
}
// 微信支付实现
public class WechatPay implements PaymentMethod {
@Override
public void pay(double amount) {
System.out.println("使用微信支付 " + amount + " 元");
}
}
然后,创建一个支付处理类,但是它没有使用策略模式,而是直接在内部决定了使用哪种支付方式,如下代码:
// 未使用策略模式的支付处理类
public class PaymentProcessor {
// 假设这里硬编码选择了支付宝支付
private PaymentMethod method = new Alipay();
// client调用此方法来进行支付
public void processPayment(double amount) {
// 这里直接调用了内部选择的支付方式
method.pay(amount);
}
// 假设有一个方法可以切换支付方式,但实际上这种切换是硬编码的,不够灵活
public void setPaymentMethodToAlipay() {
this.method = new Alipay();
}
public void setPaymentMethodToWechatPay() {
this.method = new WechatPay();
}
}
现在,编写client代码来调用这个支付处理类,如下代码:
public class Client {
public static void main(String[] args) {
// 创建支付处理对象
PaymentProcessor processor = new PaymentProcessor();
// 调用支付方法
processor.processPayment(100.0); // 输出:使用支付宝支付 100.0 元
// 尝试切换支付方式到微信支付
processor.setPaymentMethodToWechatPay();
processor.processPayment(200.0); // 输出:使用微信支付 200.0 元
// 假设系统升级,需要添加新的支付方式,那么就需要修改PaymentProcessor类
// 这违反了开闭原则,因为添加新功能需要修改已有代码
}
}
在这个反例中,PaymentProcessor
类内部硬编码了支付方式的选择逻辑,虽然提供了切换支付方式的方法,但是这种方式不够灵活,因为每次添加新的支付方式都需要修改 PaymentProcessor
类,此外,如果需要在运行时根据用户的选择或其他条件动态切换支付方式,这种硬编码的方式就无法满足需求。
使用策略模式可以很好地解决这个问题,通过将支付方式封装为策略对象,并在运行时动态地传递给上下文对象(比如 PaymentProcessor
),可以更加灵活和可扩展地管理支付方式,如下面正例。
正例
下面是一个使用策略模式的正例代码实现,在这个例子中,同样有一个支付系统,它支持多种支付方式,包括支付宝、微信支付等,通过使用策略模式,可以动态地选择支付方式,而不需要修改支付处理类的代码,如下代码:
// 支付策略接口
public interface PaymentStrategy {
void pay(double amount);
}
// 支付宝支付策略实现
public class AlipayStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付 " + amount + " 元");
}
}
// 微信支付策略实现
public class WechatPayStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("使用微信支付 " + amount + " 元");
}
}
接着,创建一个支付上下文类,它可以根据client的选择来动态地切换支付策略,如下代码:
// 支付上下文类,使用策略模式
public class PaymentContext {
// 持有支付策略的引用
private PaymentStrategy strategy;
// 构造函数,接收支付策略作为参数
public PaymentContext(PaymentStrategy strategy) {
this.strategy = strategy;
}
// 执行支付
public void executePayment(double amount) {
strategy.pay(amount);
}
// 在运行时动态改变支付策略
public void setStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
}
最后,编写client代码来演示如何使用策略模式进行支付,如下代码:
public class Client {
public static void main(String[] args) {
// 创建支付上下文对象,并设置支付策略为支付宝
PaymentContext context = new PaymentContext(new AlipayStrategy());
context.executePayment(100.0); // 输出:使用支付宝支付 100.0 元
// 动态切换支付策略到微信支付
context.setStrategy(new WechatPayStrategy());
context.executePayment(200.0); // 输出:使用微信支付 200.0 元
// 假设需要添加新的支付方式(比如银联支付),只需实现PaymentStrategy接口
// 而不需要修改PaymentContext类或其他已有的支付策略类,这符合开闭原则
}
}
在这个正例中,通过策略模式实现了支付方式的动态切换,client代码可以根据需要在运行时选择不同的支付策略,而不需要修改支付上下文类的代码。如果以后需要添加新的支付方式,只需要实现PaymentStrategy
接口,并创建相应的策略实现类即可,这完全符合开闭原则,提高了系统的灵活性和可扩展性。
核心总结
策略模式在Java开发过程中非常的实用,它让算法或行为能随需切换,增强了系统的灵活性与扩展性,当业务逻辑复杂、需多种算法并行时,策略模式可避免大量条件判断,使代码更简洁、易维护,但是,策略模式也存在很大的问题,它可能增加系统类和对象的数量,导致额外的开销,同时,client必须了解所有策略,才能选择合适的策略,这有时会增加client的复杂性,对于对于变化频繁、需求多样的场景,策略模式是不二之选;而对于稳定、简单的业务逻辑,过度使用策略模式可能适得其反。
个人思考
策略模式和责任链模式有什么区别?
策略模式关注的是如何根据不同的策略或算法来执行特定的任务,它允许在运行时根据需要动态地选择不同的策略,在策略模式中,client通常知道所有的策略,并且负责选择使用哪一个,它的优点是提供了更好的扩展性,因为添加新的策略只需要实现相应的策略接口,而不需要修改已有的代码。
相比之下,责任链模式则关注的是如何将请求沿着一个处理链进行传递,直到有一个处理者能够处理它为止。在责任链模式中,每个处理者都对请求进行检查,看自己是否能够处理,如果不能处理,则将请求传递给链中的下一个处理者,client通常不知道链中的具体处理者,也不需要关心请求是如何被处理的,这种模式的优点是减少了请求的发送者和接收者之间的耦合,因为发送者只需要知道链中的第一个处理者即可。
总结:策略模式更关注于根据不同的策略来执行任务,而责任链模式更关注于将请求沿着一个处理链进行传递。