[代碼結構設計]根據不同條件使用不同實現類的業務代碼設計


場景

此時有一個場景,需要設計一個根據不同的狀態和條件采用不同的業務處理方式。

這樣大家可能不是太理解。舉個例子,現在大街小巷上的商戶都采用了聚合支付的支付方式,聚合支付也就是商戶櫃台前放了一個支持支付寶、微信、京東錢包、銀聯等等的二維碼,用戶可以通過任意一款支付APP進行支付。

解決思路

思路①

對每個支付渠道進行定義枚舉類型

public enum PayWay {
    ALI_PAY,

    WECHAT_PAY;
}

然后在每個對應的service上定義注解,表示對應哪種支付方式

@Pay(PayWay.ALI_PAY)
public class AliPayServiceImpl implements PayService  {}

但是仔細思考后,還是存在一些問題

  1. 如果增加一個支付方式后還需要修改,PayWay這個枚舉類型
  2. 在程序中,仍需要根據不同的條件做if else判斷PayWay,增加支付方式還是得修改原有的判斷邏輯。偽代碼如下
if("xxx" == "aliPay"){
    
} else if("xxx" == "wechatPay"){
    
}
//如果增加支付方式還是得增加else if

思路②

在思路①中存在一些問題,首當其沖的就是if else判斷問題。先思考一下這個if else的作用是什么?

答:根據思路①描述,這個if else是用來確定采用哪種支付方式。

我們可以將這塊代碼抽離出來,讓對應的業務實現類實現自己的邏輯實現,然后根據返回值true 或者false決定是否過濾掉這個業務實現類。接口定義如下,SupportBean是封裝的一個實體

boolean isSupport(SupportBean supportBean);

然后在各個業務實現類都實現自己的isSupport方法,偽代碼如下

@Override
public boolean isSupport(SupportBean supportBean) {
    if (supportBean.getType() == "xxx"){
        return true;
    }
    
    return false;
}

設計

注:只提供一個架子

接口定義

Service接口定義,一個業務執行方法execute(參數自行添加),一個isSupport方法(返回true或者false

public interface Service {

    void execute();

    boolean isSupport(SupportBean supportBean);
}

業務實現類

這里execute方法只是在控制台打印字符串。isSupport方法對SupportBean中的supportNum進行取余,判斷余數是否等於0,是則返回true。

類似的實現還有兩個,這里就不貼出來了。

@Component
public class AServiceImpl implements Service {
    @Override
    public void execute() {
        System.out.println("A execute");
    }

    @Override
    public boolean isSupport(SupportBean supportBean) {
        return supportBean.getSupportNum() % 3 == 0;
    }
}

接下來在定義一個幫助類

幫助類

@Component
public class Helper {

    @Autowired
    private List<Service> services;

    public void execute(SupportBean supportBean){

        Service s = services.stream()
                .filter((service) -> service.isSupport(supportBean))
                .findFirst()//NPE異常
                .orElse(null);


        if (s != null){
            s.execute();
        }
    }
}

通過工具類的execute方法來獲取對應的業務實現類執行的結果,以及對傳入的參數進行校驗處理等。

需要注意的是Lambda表達式的findFirst()會出現NullPointException異常。因為filter對list進行過濾,會存在過濾完list的長度為0,如果此時在調用findFirst則會拋出NullPointException。可以將上面的代碼修改為如下代碼,這樣就可以避免NPE了

Service s = services.stream()
        .filter((service) -> service.isSupport(supportBean))
        .map(Optional::ofNullable)
        .findFirst()
        .flatMap(Function.identity())
        .orElse(null);

測試

添加一個springboot測試類和一個測試方法。

在contextLoads測試中調用幫助類Helper的execute方法

@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {

    @Autowired
    private Helper Helper;

    @Test
    public void contextLoads() {
        Helper.execute(new SupportBean(3));
    }

}

測試結果

A execute

擴展

在Lambda表達式中是先將業務實現類進行過濾,然后獲取第一個業務實現類並執行。

如果此時過濾存在多個業務實現類,而又不能確定優先級,這時需要如何進行擴展呢?

其實很簡單,先在Service接口中定義一個getPriority方法

int getPriority();

然后各自的實現類實現對應的getPriority方法

接着修改Lambda表達式即可,在filter后增加sorted方法即可對業務實現類進行排序

Service s = services.stream()
        .filter((service) -> service.isSupport(supportBean))
        .sorted(Comparator.comparing(Service::getPriority))
        .map(Optional::ofNullable)
        .findFirst()
        .flatMap(Function.identity())
        .orElse(null);

總結

整個大體框架基本都搭建完成,如需擴展只需要增加對應的業務實現類,而不用去修改其他類的代碼。就連之前設計的枚舉都可以不用,可擴展性大大提升。如需使用,只需修改對應的入參和對應的名稱即可。
Github地址
如果對你有收獲,歡迎star、歡迎fork
如果你也有類似的經驗,歡迎加入,一起共建


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM