一般去除多余的if else的代码,我们都是推荐使用策略设计模式。
策略设计模式一般使用的场景是,多种可互相替代的同类行为,在具体的运行过程中根据不同的情况,选择其中一种行为来执行,比如支付,有微信支付,支付宝支付,银行卡支付,那么到底使用哪种支付方式,这是由用户来决定的,再比如购物优惠,用户可以选择使用优惠券,可以选择满减优惠,以及其他优惠方式,到底是使用优惠券,还是满减,或者其他优惠方式,还是由用户来决定,类似的场景我们都可以考虑使用策略设计模式,可能对于类似的场景我们最常用的还是if-else,if-else的缺点是缺少扩展性,从6大原则来说不符合开闭原则,下面我们通过一个实际的场景来看下策略设计模式如何使用。
//信用卡
if (xx==creditCard){
//现金
} else if (xx==cash) {
//贝宝支付
} else if (xx==paypal) {
}
对于这些代码,其实都是用于支付,但是支付的逻辑不通,这时候我们就可以考虑采用策略设计模式进行改造,使代码看起来更加优美。
首先,我们定义一个接口 PaymentStrategy,表示支付策略,它包含一个 pay 方法:
public interface PaymentStrategy {
public void pay(double amount);
}
接下来,我们定义两个具体的支付策略类,分别是 CreditCardPaymentStrategy、PaypalPaymentStrategy,它们实现了 PaymentStrategy 接口:
public class CreditCardPaymentStrategy implements PaymentStrategy {
private String name;
private String cardNumber;
private String cvv;
private String dateOfExpiry;
public CreditCardPaymentStrategy(String name, String cardNumber, String cvv, String dateOfExpiry) {
this.name = name;
this.cardNumber = cardNumber;
this.cvv = cvv;
this.dateOfExpiry = dateOfExpiry;
}
@Override
public void pay(double amount) {
System.out.println(amount + " paid with credit/debit card");
}
}
public class PaypalPaymentStrategy implements PaymentStrategy {
private String email;
private String password;
public PaypalPaymentStrategy(String email, String password) {
this.email = email;
this.password = password;
}
@Override
public void pay(double amount) {
System.out.println("Pay " + amount + " with Paypal");
}
}
接下来,我们需要定义一个Context类,它将使用策略接口来执行相应的策略:
public class PaymentContext {
private PaymentStrategy strategy;
public PaymentContext(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void pay(double amount) {
strategy.pay(amount);
}
}
最后,我们可以使用上面定义的类来演示策略模式的使用:
public class StrategyPatternExample {
public static void main(String[] args) {
PaymentContext context = new PaymentContext(new CreditCardPaymentStrategy("John Doe", "1234567890123456", "786", "12/22"));
context.pay(100);
context = new PaymentContext(new PayPalPaymentStrategy("[email protected]", "mypassword"));
context.pay(200);
}
}
运行结果:
100.0 paid with credit/debit card
200.0 paid using PayPal
这个示例中,我们创建了一个PaymentContext对象,并将具体的策略对象传递给它。然后,我们调用context.pay(amount)方法,其中amount是要支付的金额。context.pay(amount)方法将使用传递给它的策略对象来执行相应的支付方法。这种方式可以让我们轻松地更改使用的策略,而不需要更改客户端代码。
这样虽然实现了,但是还不够完美,可能还是需要使用if去判断,下面就使用工厂+策略的方式去重新这部分代码
支付接口
public interface PaymentStrategy extends PaymentFactory.PayFactoryType{
public void pay(double amount);
}
支付实现类
@Component
public class CreditCardPaymentStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println(amount + " paid with credit/debit card");
}
@Override
public PaymentFactory.PayType register() {
return PaymentFactory.PayType.CREDIT_CARD;
}
}
@Component
public class PayPalPaymentStrategy implements PaymentStrategy{
@Override
public void pay(double amount) {
System.out.println(amount + " paid using PayPal");
}
@Override
public PaymentFactory.PayType register() {
return PaymentFactory.PayType.PAY_PAL;
}
}
工厂类型
package cn.phlos.pattern.two;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class PaymentFactory {
//定义一个支付类的集合,用来存储不同的支付类
private static Map PAY_MAP = new ConcurrentHashMap<>();
//使用了spring加载PaymentStrategy接口的所有的bean
@Autowired
private List paymentStrategyList;
//初始化时候,将实现了PaymentStrategy接口的所有的bean的类都注入到PAY_MAP里
@PostConstruct
public void init() {
for (PaymentStrategy paymentStrategy : paymentStrategyList) {
register(paymentStrategy.register(), paymentStrategy);
}
}
//注册方法
private void register(PayType payType, PaymentStrategy paymentStrategy) {
if (ObjectUtils.isEmpty(paymentStrategy) || ObjectUtils.isEmpty(payType)) {
return;
}
PAY_MAP.put(payType, paymentStrategy);
}
//根据不同的类型去获取不同的支付类
public static PaymentStrategy getPaymentStrategy(Integer type) {
if (ObjectUtils.isEmpty(type)) {
return null;
}
return PAY_MAP.get(PayType.getPayType(type));
}
//定义一个支付的类型enum,用途是为了区分当前的支付类所对应的类型,通过该类型可以快速拿个对应的对象
enum PayType {
CREDIT_CARD(1),
PAY_PAL(2);
int type;
PayType(int type) {
this.type = type;
}
public static PayType getPayType(Integer type) {
if (ObjectUtils.isEmpty(type)) {
return null;
}
for (PayType value : values()) {
if (value.type == type) {
return value;
}
}
return null;
}
}
//定义一个接口,让当前的策略支付接口去继承,也可以把当前注册方法写在策略支付接口
interface PayFactoryType {
PayType register();
}
}
测试方法:
@Test
void contextLoads() {
PaymentFactory.getPaymentStrategy(1).pay(0.1);
PaymentFactory.getPaymentStrategy(2).pay(0.1);
}
结果:
0.1 paid with credit/debit card
0.1 paid using PayPal
工厂+策略模式,在这里是采用了spring的介入去实现。因为考虑到我们会使用不同的类型去区分支付类型,可以通过一个map的形式去存储这些支付类型,形式为:key:类型,value:支付实现类。通过这样的方式,我们就能快速的拿到相关的支付实现类,从而可以抛弃繁杂的if-else逻辑。
从一定的意义上,可能if-else这样更加直观,对于初学者或是面向过程编程的小伙伴会比较友好,能快速的知道逻辑的走向。