[代碼結(jié)構(gòu)設(shè)計(jì)]根據(jù)不同條件使用不同實(shí)現(xiàn)類的業(yè)務(wù)代碼設(shè)計(jì)

場景

此時(shí)有一個(gè)場景,需要設(shè)計(jì)一個(gè)根據(jù)不同的狀態(tài)和條件采用不同的業(yè)務(wù)處理方式。

這樣大家可能不是太理解。舉個(gè)例子,現(xiàn)在大街小巷上的商戶都采用了聚合支付的支付方式,聚合支付也就是商戶柜臺(tái)前放了一個(gè)支持支付寶、微信、京東錢包、銀聯(lián)等等的二維碼,用戶可以通過任意一款支付APP進(jìn)行支付。

解決思路

思路①

對每個(gè)支付渠道進(jìn)行定義枚舉類型

public enum PayWay {
    ALI_PAY,

    WECHAT_PAY;
}

然后在每個(gè)對應(yīng)的service上定義注解,表示對應(yīng)哪種支付方式

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

但是仔細(xì)思考后,還是存在一些問題

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

思路②

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

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

我們可以將這塊代碼抽離出來,讓對應(yīng)的業(yè)務(wù)實(shí)現(xiàn)類實(shí)現(xiàn)自己的邏輯實(shí)現(xiàn),然后根據(jù)返回值true 或者false決定是否過濾掉這個(gè)業(yè)務(wù)實(shí)現(xiàn)類。接口定義如下,SupportBean是封裝的一個(gè)實(shí)體

boolean isSupport(SupportBean supportBean);

然后在各個(gè)業(yè)務(wù)實(shí)現(xiàn)類都實(shí)現(xiàn)自己的isSupport方法,偽代碼如下

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

設(shè)計(jì)

注:只提供一個(gè)架子

接口定義

Service接口定義,一個(gè)業(yè)務(wù)執(zhí)行方法execute(參數(shù)自行添加),一個(gè)isSupport方法(返回true或者false

public interface Service {

    void execute();

    boolean isSupport(SupportBean supportBean);
}

業(yè)務(wù)實(shí)現(xiàn)類

這里execute方法只是在控制臺(tái)打印字符串。isSupport方法對SupportBean中的supportNum進(jìn)行取余,判斷余數(shù)是否等于0,是則返回true。

類似的實(shí)現(xiàn)還有兩個(gè),這里就不貼出來了。

@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;
    }
}

接下來在定義一個(gè)幫助類

幫助類

@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方法來獲取對應(yīng)的業(yè)務(wù)實(shí)現(xiàn)類執(zhí)行的結(jié)果,以及對傳入的參數(shù)進(jìn)行校驗(yàn)處理等。

需要注意的是Lambda表達(dá)式的findFirst()會(huì)出現(xiàn)NullPointException異常。因?yàn)閒ilter對list進(jìn)行過濾,會(huì)存在過濾完list的長度為0,如果此時(shí)在調(diào)用findFirst則會(huì)拋出NullPointException??梢詫⑸厦娴拇a修改為如下代碼,這樣就可以避免NPE了

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

測試

添加一個(gè)springboot測試類和一個(gè)測試方法。

在contextLoads測試中調(diào)用幫助類Helper的execute方法

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

    @Autowired
    private Helper Helper;

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

}

測試結(jié)果

A execute

擴(kuò)展

在Lambda表達(dá)式中是先將業(yè)務(wù)實(shí)現(xiàn)類進(jìn)行過濾,然后獲取第一個(gè)業(yè)務(wù)實(shí)現(xiàn)類并執(zhí)行。

如果此時(shí)過濾存在多個(gè)業(yè)務(wù)實(shí)現(xiàn)類,而又不能確定優(yōu)先級,這時(shí)需要如何進(jìn)行擴(kuò)展呢?

其實(shí)很簡單,先在Service接口中定義一個(gè)getPriority方法

int getPriority();

然后各自的實(shí)現(xiàn)類實(shí)現(xiàn)對應(yīng)的getPriority方法

接著修改Lambda表達(dá)式即可,在filter后增加sorted方法即可對業(yè)務(wù)實(shí)現(xiàn)類進(jìn)行排序

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

總結(jié)

整個(gè)大體框架基本都搭建完成,如需擴(kuò)展只需要增加對應(yīng)的業(yè)務(wù)實(shí)現(xiàn)類,而不用去修改其他類的代碼。就連之前設(shè)計(jì)的枚舉都可以不用,可擴(kuò)展性大大提升。如需使用,只需修改對應(yīng)的入?yún)⒑蛯?yīng)的名稱即可。
Github地址
如果對你有收獲,歡迎star、歡迎fork
如果你也有類似的經(jīng)驗(yàn),歡迎加入,一起共建

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,034評論 25 709
  • 用兩張圖告訴你,為什么你的 App 會(huì)卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 13,990評論 2 59
  • 親愛的自己,大雪下了一天一夜,早上起來,只看見外面是一個(gè)銀裝素裹的世界。這場大雪給我們的出行帶來了很多不便。大家都...
    冬季飄雪閱讀 136評論 0 1
  • 聽完“VVG Chin Chin 開幕講座”,受益頗深,尤其是和朱平先生對生活理念上達(dá)成了很多共識之處,巧妙的是,...
    KJWANG閱讀 536評論 0 0
  • 你只是路過我的心間 我卻需要一生去忘卻 忘不了你在操場上奔跑的樣子 忘不了你皺眉頭的樣子 忘不了春風(fēng)吹拂你劉海的樣...
    阿亮的月亮閱讀 271評論 1 5

友情鏈接更多精彩內(nèi)容