這是在一次公司項目中進行重構時,一些複雜業務時想到的一個去掉一些if else的辦法。可以使代碼邏輯更加清晰,減小一些業務上的耦合。html
我所在的是一個作保險的項目組,此次重構是針對其中的保費計算和核保的業務。java
項目重構以前,在保費計算的接口中,有大量的條件判斷語句來判斷此次進行保費計算的產品是哪個,而後調用該產品的保費計算方法。代碼大體看起來就是這個樣子:spring
//產品編號 String product = "123123"; if (product.equals("11111")) { } else if (product.equals("11111")) { //使用產品編號是11111的service類進行保費計算 // } else if (product.equals("22222")) { //使用產品編號是22222的service類進行保費計算 // } else { //執行其餘的保費計算 }
這些經過一個編號進行判斷並執行特定代碼的方法在項目中處處都是,一旦添加了新的產品,或者產品在一些特定銷售渠道中有特定的一些操做(好比有一些折扣啊什麼的)就要在代碼的各類關鍵地方添加一堆 if eles,大大影響了代碼的可讀性和可維護性。經常是修改了一處代碼,影響到不少別的地方,形成一些看起來很奇怪的bug。數據庫
因此我在接手這個項目的時候想到了重構。但願在重構後可以使各個產品之間的代碼沒有關聯,業務分明,相互不影響。ide
重構代碼以前要先分析一下業務,由於個人這個項目是作保費計算的,雖然有一大堆的判斷產品編號的代碼,可是最終它們作的都是同一件事情。這裏能夠把保費計算抽象成爲一個接口,在接口中定義執行保費計算所須要的共同的方法。大體上是這個樣子:code
/** * 保費計算接口 * * @author hjx */ public interface PremiumCalculate { //保費計算 Result calculate(Param param); //其餘的保費計算中須要的方法 。。。 }
這一步主要是梳理一下項目中的業務,並把業務中相同的步驟抽象出來。htm
這一步就是實現上面的接口了,每一個產品實現一遍接口。這裏會存在一個問題,就是有不少產品在進行保費計算的時候,只有某幾個步驟不同。若是每一個實現上都寫一遍,會形成大量的重複代碼。對象
咱們能夠建一個抽象類來實現這個接口,將大部分共有的實現代碼寫在抽象類中。就像這樣:blog
/** * 抽象的保費計算 */ public abstract class AbstractPremiumCalculate implements PremiumCalculate { /** * 實現共有的一些代碼 * @param premiumInfo * @return */ @Override public Result calculate(Param param) { //將共有的實現寫在這裏 } }
這樣在新添加一個實現類的時候只要繼承這個抽象類,重寫其中的某些方法就能夠了。這時咱們可能有不少實現類,好比:繼承
PremiumCalculateP001Impl.java
PremiumCalculateP002Impl.java
PremiumCalculateP003Impl.java
PremiumCalculateP004Impl.java
這時就能夠在執行保費計算的時候根據不一樣的產品調用不一樣的實現。每一個實現類只寫一個產品的業務就行,類之間相互不影響。在新添加產品的時候也是隻須要添加一個新的實現類就行了。
可是這樣仍是有問題的,由於仍是要在業務代碼中寫一堆的if else 來判斷此次到底須要哪個實現類來執行保費計算,這時能夠寫一個工廠類。根據傳入的產品編號或者別的什麼參數,返回特定的一個實現類,像是這樣:
/** * 保費計算接口工廠類 */ @Service public class PremiumCalculateFactory { @Autowired @Qualifier("premiumCalculateP0001") private PremiumCalculate premiumCalculateP0001; @Autowired @Qualifier("premiumCalculateP0002") private PremiumCalculate premiumCalculateP0002; @Autowired @Qualifier("premiumCalculateP0003") private PremiumCalculate premiumCalculateP0003; @Autowired @Qualifier("premiumCalculateP0004") private PremiumCalculate premiumCalculateP0004; 。。。。其餘的保費計算實現對象 public PremiumCalculate getPremiumCalculate(String productCode) { if (productCode.equals("P0001")) { return premiumCalculateP0001; } else if () { //其餘的條件下,返回其餘的對象 } } }
添加了工廠類以後,咱們在獲取保費計算對象的時候只須要調用getPremiumCalculate()方法就能夠了,具體返回哪個實現對象,就交給工廠類來處理。能夠精簡調用保費計算時的代碼。
在提供了工廠類以後,仍是免不了寫不少的條件判斷,只不過是把全部的條件判斷寫在了一塊兒。這時隨着產品數量的增多,if else 也會不停地增多,維護起來依然費勁。
這裏spring容器就能夠排上用場了。spring中有一個BeanFactory對象,也是一個工廠,咱們能夠用它來改造PremiumCalculateFactory。
首先咱們在編寫各個產品對應的保費計算實現類的時候都會將它註冊進spring容器中,成爲一個bean。咱們須要給這個bean指定一個名稱好比:
//在這裏指定bean的名稱 @Service("PremiumCalculate:"+產品編號) public class PremiumCalculateP0001Impl implements PremiumCalculate { 。。。 }
而後修改PremiumCalculateFactory
/** * 保費計算接口工廠類 */ @Service public class PremiumCalculateFactory { @Autowired private BeanFactory beanFactory; public PremiumCalculate getPremiumCalculate(String productCode) { Object bean = beanFactory.getBean("PremiumCalculate:" + productCode); if (bean instanceof PremiumCalculate) { return (PremiumCalculate) bean; } throw new UnsupportedOperationException("不支持的編號:" + productCode); } }
這樣,條件判斷的步驟就能夠省略了。
在保費計算和核保項目通過這樣重構後,每一個產品的業務代碼相互不關聯,維護和添加產品時也能減小工做量,仍是比較成功的。
這樣寫會有一個比較大的問題,就是在產品數量增多的時候,java文件數量也會隨之變多。可是目前的業務中產品數量還能夠忍受。因爲產品配置功能的出現,大部分產品均可以經過數據庫配置出來。這裏只是寫配不出來的一部分,因此這種模式仍是可行的。
https://www.cnblogs.com/hebaibai/p/11095590.html