日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

伪代码的简单例子_使用策略+工厂模式彻底干掉代码中的if else!

發布時間:2025/3/15 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 伪代码的简单例子_使用策略+工厂模式彻底干掉代码中的if else! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
對于業務開發來說,業務邏輯的復雜是必然的,隨著業務發展,需求只會越來越復雜,為了考慮到各種各樣的情況,代碼中不可避免的會出現很多if-else。

一旦代碼中if-else過多,就會大大的影響其可讀性和可維護性。

首先可讀性,不言而喻,過多的if-else代碼和嵌套,會使閱讀代碼的人很難理解到底是什么意思。尤其是那些沒有注釋的代碼。

其次是可維護性,因為if-else特別多,想要新加一個分支的時候,就會很難添加,極其容易影響到其他的分支。

筆者曾經看到過一個支付的核心應用,這個應用支持了很多業務的線上支付功能,但是每個業務都有很多定制的需求,所以很多核心的代碼中都有一大坨if-else。

每個新業務需要定制的時候,都把自己的if放到整個方法的最前面,以保證自己的邏輯可以正常執行。這種做法,后果可想而知。

其實,if-else是有辦法可以消除掉的,其中比較典型的并且使用廣泛的就是借助策略模式和工廠模式,準確的說是利用這兩個設計模式的思想,徹底消滅代碼中的if-else。

本文,就結合這兩種設計模式,介紹如何消除if-else,并且,還會介紹如何和Spring框架結合,這樣讀者看完本文之后就可以立即應用到自己的項目中。

本文涉及到一些代碼,但是作者盡量用通俗的例子和偽代碼等形式使內容不那么枯燥。

惡心的if-else

假設我們要做一個外賣平臺,有這樣的需求:

1、外賣平臺上的某家店鋪為了促銷,設置了多種會員優惠,其中包含超級會員折扣8折、普通會員折扣9折和普通用戶沒有折扣三種。

2、希望用戶在付款的時候,根據用戶的會員等級,就可以知道用戶符合哪種折扣策略,進而進行打折,計算出應付金額。

3、隨著業務發展,新的需求要求專屬會員要在店鋪下單金額大于30元的時候才可以享受優惠。

4、接著,又有一個變態的需求,如果用戶的超級會員已經到期了,并且到期時間在一周內,那么就對用戶的單筆訂單按照超級會員進行折扣,并在收銀臺進行強提醒,引導用戶再次開通會員,而且折扣只進行一次。

那么,我們可以看到以下偽代碼:

public?BigDecimal?calPrice(BigDecimal?orderPrice,?String?buyerType)?{

????if?(用戶是專屬會員)?{
????????if?(訂單金額大于30元)?{
????????????returen?7折價格;
????????}
????}

????if?(用戶是超級會員)?{
????????return?8折價格;
????}

????if?(用戶是普通會員)?{
????????if(該用戶超級會員剛過期并且尚未使用過臨時折扣){
????????????臨時折扣使用次數更新();
????????????returen?8折價格;
????????}
????????return?9折價格;
????}
????return?原價;
}

以上,就是對于這個需求的一段價格計算邏輯,使用偽代碼都這么復雜,如果是真的寫代碼,那復雜度可想而知。

這樣的代碼中,有很多if-else,并且還有很多的if-else的嵌套,無論是可讀性還是可維護性都非常低。

那么,如何改善呢?

策略模式

接下來,我們嘗試引入策略模式來提升代碼的可維護性和可讀性。

首先,定義一個接口:

/**
?*?@author?mhcoding
?*/
public?interface?UserPayService?{

????/**
?????*?計算應付價格
?????*/
????public?BigDecimal?quote(BigDecimal?orderPrice);
}

接著定義幾個策略類:

/**
?*?@author?mhcoding
?*/
public?class?ParticularlyVipPayService?implements?UserPayService?{

????@Override
????public?BigDecimal?quote(BigDecimal?orderPrice)?{
?????????if?(消費金額大于30元)?{
????????????return?7折價格;
????????}
????}
}

public?class?SuperVipPayService?implements?UserPayService?{

????@Override
????public?BigDecimal?quote(BigDecimal?orderPrice)?{
????????return?8折價格;
????}
}

public?class?VipPayService?implements?UserPayService?{

????@Override
????public?BigDecimal?quote(BigDecimal?orderPrice)?{
????????if(該用戶超級會員剛過期并且尚未使用過臨時折扣){
????????????臨時折扣使用次數更新();
????????????returen?8折價格;
????????}
????????return?9折價格;
????}
}

引入了策略之后,我們可以按照如下方式進行價格計算:

/**
?*?@author?mhcoding
?*/
public?class?Test?{

????public?static?void?main(String[]?args)?{
????????UserPayService?strategy?=?new?VipPayService();
????????BigDecimal?quote?=?strategy.quote(300);
????????System.out.println("普通會員商品的最終價格為:"?+?quote.doubleValue());

????????strategy?=?new?SuperVipPayService();
????????quote?=?strategy.quote(300);
????????System.out.println("超級會員商品的最終價格為:"?+?quote.doubleValue());
????}
}

以上,就是一個例子,可以在代碼中new出不同的會員的策略類,然后執行對應的計算價格的方法。這個例子以及策略模式的相關知識,讀者可以在《如何給女朋友解釋什么是策略模式?》一文中學習。

但是,真正在代碼中使用,比如在一個web項目中使用,上面這個Demo根本沒辦法直接用。

首先,在web項目中,上面我們創建出來的這些策略類都是被Spring托管的,我們不會自己去new一個實例出來。

其次,在web項目中,如果真要計算價格,也是要事先知道用戶的會員等級,比如從數據庫中查出會員等級,然后根據等級獲取不同的策略類執行計算價格方法。

那么,web項目中真正的計算價格的話,偽代碼應該是這樣的:

/**
?*?@author?mhcoding
?*/
public?BigDecimal?calPrice(BigDecimal?orderPrice,User?user)?{

?????String?vipType?=?user.getVipType();

?????if?(vipType?==?專屬會員)?{
????????//偽代碼:從Spring中獲取超級會員的策略對象
????????UserPayService?strategy?=?Spring.getBean(ParticularlyVipPayService.class);
????????return?strategy.quote(orderPrice);
?????}

?????if?(vipType?==?超級會員)?{
????????UserPayService?strategy?=?Spring.getBean(SuperVipPayService.class);
????????return?strategy.quote(orderPrice);
?????}

?????if?(vipType?==?普通會員)?{
????????UserPayService?strategy?=?Spring.getBean(VipPayService.class);
????????return?strategy.quote(orderPrice);
?????}
?????return?原價;
}

通過以上代碼,我們發現,代碼可維護性和可讀性好像是好了一些,但是好像并沒有減少if-else啊。

其實,在之前的《如何給女朋友解釋什么是策略模式?》一文中,我們介紹了很多策略模式的優點。但是,策略模式的使用上,還是有一個比較大的缺點的:

客戶端必須知道所有的策略類,并自行決定使用哪一個策略類。這就意味著客戶端必須理解這些算法的區別,以便適時選擇恰當的算法類。

也就是說,雖然在計算價格的時候沒有if-else了,但是選擇具體的策略的時候還是不可避免的還是要有一些if-else。

另外,上面的偽代碼中,從Spring中獲取會員的策略對象我們是偽代碼實現的,那么代碼到底該如何獲取對應的Bean呢?

接下來我們看如何借助Spring和工廠模式,解決上面這些問題。

工廠模式

為了方便我們從Spring中獲取UserPayService的各個策略類,我們創建一個工廠類:

/**
?*?@author?mhcoding
?*/
public?class?UserPayServiceStrategyFactory?{

????private?static?Map?services?=?new?ConcurrentHashMap();public??static?UserPayService?getByUserType(String?type){return?services.get(type);
????}public?static?void?register(String?userType,UserPayService?userPayService){
????????Assert.notNull(userType,"userType?can't?be?null");
????????services.put(userType,userPayService);
????}
}

這個UserPayServiceStrategyFactory中定義了一個Map,用來保存所有的策略類的實例,并提供一個getByUserType方法,可以根據類型直接獲取對應的類的實例。還有一個register方法,這個后面再講。

有了這個工廠類之后,計算價格的代碼即可得到大大的優化:

/**
?*?@author?mhcoding
?*/
public?BigDecimal?calPrice(BigDecimal?orderPrice,User?user)?{

?????String?vipType?=?user.getVipType();
?????UserPayService?strategy?=?UserPayServiceStrategyFactory.getByUserType(vipType);
?????return?strategy.quote(orderPrice);
}

以上代碼中,不再需要if-else了,拿到用戶的vip類型之后,直接通過工廠的getByUserType方法直接調用就可以了。

通過策略+工廠,我們的代碼很大程度的優化了,大大提升了可讀性和可維護性。

但是,上面還遺留了一個問題,那就是UserPayServiceStrategyFactory中用來保存所有的策略類的實例的Map是如何被初始化的?各個策略的實例對象如何塞進去的呢?

Spring Bean的注冊

還記得我們前面定義的UserPayServiceStrategyFactory中提供了的register方法嗎?他就是用來注冊策略服務的。

接下來,我們就想辦法調用register方法,把Spring通過IOC創建出來的Bean注冊進去就行了。

這種需求,可以借用Spring種提供的InitializingBean接口,這個接口為Bean提供了屬性初始化后的處理方法,它只包括afterPropertiesSet方法,凡是繼承該接口的類,在bean的屬性初始化后都會執行該方法。

那么,我們將前面的各個策略類稍作改造即可:

/**
?*?@author?mhcoding
?*/
@Service
public?class?ParticularlyVipPayService?implements?UserPayService,InitializingBean?{

????@Override
????public?BigDecimal?quote(BigDecimal?orderPrice)?{
?????????if?(消費金額大于30元)?{
????????????return?7折價格;
????????}
????}

????@Override
????public?void?afterPropertiesSet()?throws?Exception?{
????????UserPayServiceStrategyFactory.register("ParticularlyVip",this);
????}
}

@Service
public?class?SuperVipPayService?implements?UserPayService?,InitializingBean{

????@Override
????public?BigDecimal?quote(BigDecimal?orderPrice)?{
????????return?8折價格;
????}

????@Override
????public?void?afterPropertiesSet()?throws?Exception?{
????????UserPayServiceStrategyFactory.register("SuperVip",this);
????}
}

@Service??
public?class?VipPayService?implements?UserPayService,InitializingBean?{

????@Override
????public?BigDecimal?quote(BigDecimal?orderPrice)?{
????????if(該用戶超級會員剛過期并且尚未使用過臨時折扣){
????????????臨時折扣使用次數更新();
????????????returen?8折價格;
????????}
????????return?9折價格;
????}

????@Override
????public?void?afterPropertiesSet()?throws?Exception?{
????????UserPayServiceStrategyFactory.register("Vip",this);
????}
}

只需要每一個策略服務的實現類都實現InitializingBean接口,并實現其afterPropertiesSet方法,在這個方法中調用UserPayServiceStrategyFactory.register即可。

這樣,在Spring初始化的時候,當創建VipPayService、SuperVipPayService和ParticularlyVipPayService的時候,會在Bean的屬性初始化之后,把這個Bean注冊到UserPayServiceStrategyFactory中。

以上代碼,其實還是有一些重復代碼的,這里面還可以引入模板方法模式進一步精簡,這里就不展開了。

還有就是,UserPayServiceStrategyFactory.register調用的時候,第一個參數需要傳一個字符串,這里的話其實也可以優化掉。比如使用枚舉,或者在每個策略類中自定義一個getUserType方法,各自實現即可。

總結

本文,我們通過策略模式、工廠模式以及Spring的InitializingBean,提升了代碼的可讀性以及可維護性,徹底消滅了一坨if-else。

文中的這種做法,大家可以立刻嘗試起來,這種實踐,是我們日常開發中經常用到的,而且還有很多衍生的用法,也都非常好用。有機會后面再介紹。

其實,如果讀者們對策略模式和工廠模式了解的話,文中使用的并不是嚴格意義上面的策略模式和工廠模式。

首先,策略模式中重要的Context角色在這里面是沒有的,沒有Context,也就沒有用到組合的方式,而是使用工廠代替了。

另外,這里面的UserPayServiceStrategyFactory其實只是維護了一個Map,并提供了register和get方法而已,而工廠模式其實是幫忙創建對象的,這里并沒有用到。

所以,讀者不必糾結于到底是不是真的用了策略模式和工廠模式。而且,這里面也再擴展一句,所謂的GOF 23種設計模式,無論從哪本書或者哪個博客看,都是簡單的代碼示例,但是我們日常開發很多都是基于Spring等框架的,根本沒辦法直接用的。

所以,對于設計模式的學習,重要的是學習其思想,而不是代碼實現!!!

推薦閱讀

  • 后端程序員必備:Mysql數據庫相關流程圖/原理圖
  • 【真實生產案例】消息中間件如何處理消費失敗的消息?
  • 你不會還在用這8個錯誤的SQL寫法吧?
  • Sql Or NoSql,看完這一篇你就都懂了
  • 沒看這篇干貨,別說你會使用“緩存”
  • 我的Github開源項目,從0到20000 Star!
  • Spring Cloud Gateway:新一代API網關服務
  • Spring Cloud Consul:服務治理與配置中心
  • Spring Cloud Sleuth:分布式請求鏈路跟蹤
  • Spring Cloud Bus:消息總線
  • Spring Cloud Config:外部集中化配置管理
  • Spring Cloud Zuul:API網關服務

歡迎關注,點個在看

總結

以上是生活随笔為你收集整理的伪代码的简单例子_使用策略+工厂模式彻底干掉代码中的if else!的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。