1. 引入
假设现在要设计一个支付系统,需要支持三种支付方式:
- 微信支付
- 支付宝支付
- 银行卡支付
针对不同的支付方式,有不同的支付逻辑,以下是两种设计方案。
1.1 方案一:if-else实现
1.1.1 实现代码
public class PaymentApp {
public static void main(String[] args) {
String payment = "";
Double amount = 100.0;
if(payment = "AliPay"){
// 使用支付宝支付
payWithAliPay(amount);
}
if(payment = "WeChatPay"){
// 使用微信支付
payWithWeChatPay(amount);
}
if(payment = "CreditCard"){
// 使用信用卡支付
payWithCreditCard("1234567890123456", "123", amount);
}
}
public static void payWithAliPay(double amount) {
System.out.println("使用支付宝支付,金额为:" + amount);
// 支付宝实际支付逻辑
}
public static void payWithWeChatPay(double amount) {
System.out.println("使用微信支付,金额为: " + amount);
// 微信实际支付逻辑
}
public static void payWithCreditCard(String cardNumber, String cvv, double amount) {
System.out.println("使用信用卡支付:" + cardNumber.substring(cardNumber.length() - 4) + "金额为: " + amount);
// 信用卡实际支付逻辑
}
}
1.1.2 上述方案存在问题
-
代码臃肿:随着支付方式增多,要写多条
if-else语句,导致代码的可读性较差,且难以维护; -
违背了开闭原则:如果每次新增或者修改支付方式,都需要修改代码;
-
复用性差:支付逻辑无法复用。
1.2 使用策略模式实现
1.2.1 实现代码
- 定义策略接口
PaymentStrategy
// 策略接口
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);
// 实际支付逻辑
}
}
// 信用卡支付策略
public class CreditCardPayStrategy implements PaymentStrategy {
private String cardNumber;
private String cvv;
public CreditCardPayStrategy(String cardNumber, String cvv) {
this.cardNumber = cardNumber;
this.cvv = cvv;
}
@Override
public void pay(double amount) {
System.out.println("Paid using Credit Card ending with " + cardNumber.substring(cardNumber.length() - 4) + ": $" + amount);
// 实际支付逻辑
}
}
- 定义上下文类
PaymentContext
// 上下文类
public class PaymentContext {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy paymentStrategy){
this.paymentStrategy = paymentStrategy;
}
public void performPayment(double amount) {
if (paymentStrategy == null) {
throw new IllegalStateException("Payment strategy is not set.");
}
paymentStrategy.pay(amount);
}
}
1.2.2 上述方案优点
-
算法的实现与使用逻辑隔离;
-
符合开闭原则
2. 策略模式
2.1 定义
策略模式(Strategy Pattern)/ 政策模式(Policy Pattern):一种行为设计模式,能定义一系列算法,并将每种算法分别放入独立的类中,以使算法的对象能够相互替换。
【例如】如果想要去往机场,可以根据自己的实际情况选择适合自己的出行策略。
2.2 角色及结构
2.2.1 策略模式三大角色
-
Context上下文角色:承上启下的封装作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化; -
Strategy抽象策略角色:定义每个策略或算法必须有的方法和属性; -
ConcreteStrategy具体策略角色:实现抽象策略中的操作,定义具体的算法实现逻辑
2.2.2 结构
2.3 适用场景
-
多个类只有在算法或行为上稍有不同;
-
算法需要自由切换;
-
算法在上下文的逻辑中不是特别重要,使用策略模式能将类的业务逻辑和算法实现细节隔离;
2.4 优缺点
2.4.1 优点
-
算法可以自由切换;
-
避免使用多重条件判断;
-
可以将算法的实现和使用算法的代码隔离;
-
扩展性良好:系统新增策略只需要实现接口,不需要修改其他代码,符合开闭原则。
2.4.2 缺点
-
策略数量增多:每一个策略都是一个类,复用可能性较小;
-
所有策略类都要对外暴露:上层模块必须知道有哪些策略才能决定使用哪一个策略。
2.5 注意事项
如果系统中的一个策略家族的具体策略数量超过4个,需要考虑混合模式,用于解决策略类膨胀和对外暴露的问题,否则日后的系统维护工作比较难。
参考资料
- 《设计模式之禅》
- refactoringguru.cn/design-patt…