手把手教你去除代码过多的if else代码(工厂+策略)

一般去除多余的if else的代码,我们都是推荐使用策略设计模式。

策略设计模式一般使用的场景是,多种可互相替代的同类行为,在具体的运行过程中根据不同的情况,选择其中一种行为来执行,比如支付,有微信支付,支付宝支付,银行卡支付,那么到底使用哪种支付方式,这是由用户来决定的,再比如购物优惠,用户可以选择使用优惠券,可以选择满减优惠,以及其他优惠方式,到底是使用优惠券,还是满减,或者其他优惠方式,还是由用户来决定,类似的场景我们都可以考虑使用策略设计模式,可能对于类似的场景我们最常用的还是if-else,if-else的缺点是缺少扩展性,从6大原则来说不符合开闭原则,下面我们通过一个实际的场景来看下策略设计模式如何使用。

一、现实中有很多类似为if else这些代码

//信用卡
if (xx==creditCard){

    //现金
} else if (xx==cash) {
    //贝宝支付
} else if (xx==paypal) {

}

对于这些代码,其实都是用于支付,但是支付的逻辑不通,这时候我们就可以考虑采用策略设计模式进行改造,使代码看起来更加优美。

二、策略模式优化代码

首先,我们定义一个接口 PaymentStrategy,表示支付策略,它包含一个 pay 方法:

public interface PaymentStrategy {
    public void pay(double amount);
}

接下来,我们定义两个具体的支付策略类,分别是 CreditCardPaymentStrategyPaypalPaymentStrategy,它们实现了 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<PayType, PaymentStrategy> PAY_MAP = new ConcurrentHashMap<>();

    //使用了spring加载PaymentStrategy接口的所有的bean
    @Autowired
    private List<PaymentStrategy> 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这样更加直观,对于初学者或是面向过程编程的小伙伴会比较友好,能快速的知道逻辑的走向。

猜你喜欢

转载自blog.csdn.net/wssc63262/article/details/129075358