免费爱碰视频在线观看,九九精品国产屋,欧美亚洲尤物久久精品,1024在线观看视频亚洲

      移除 if-else

      移除 if-else

      前言

      物流行業(yè)中,通常會涉及到EDI報(bào)文(XML格式文件)傳輸和回執(zhí)接收,每發(fā)送一份EDI報(bào)文,后續(xù)都會收到與之關(guān)聯(lián)的回執(zhí)(標(biāo)識該數(shù)據(jù)在第三方系統(tǒng)中的流轉(zhuǎn)狀態(tài))。

      這里枚舉幾種回執(zhí)類型:MT1101、MT2101、MT4101、MT8104、MT8105、MT9999,系統(tǒng)在收到不同的回執(zhí)報(bào)文后,會執(zhí)行對應(yīng)的業(yè)務(wù)邏輯處理。當(dāng)然,實(shí)際業(yè)務(wù)場景并沒有那么籠統(tǒng),這里以回執(zhí)處理為演示案例

      模擬一個回執(zhí)類

      @Datapublic class Receipt { /** * 回執(zhí)信息 */ String message; /** * 回執(zhí)類型(`MT1101、MT2101、MT4101、MT8104、MT8105、MT9999`) */ String type;}

      模擬一個回執(zhí)生成器

      public class ReceiptBuilder { public static List generateReceiptList(){ //直接模擬一堆回執(zhí)對象 List receiptList = new ArrayList(); receiptList.add(new Receipt(“我是MT2101回執(zhí)喔”,”MT2101″)); receiptList.add(new Receipt(“我是MT1101回執(zhí)喔”,”MT1101″)); receiptList.add(new Receipt(“我是MT8104回執(zhí)喔”,”MT8104″)); receiptList.add(new Receipt(“我是MT9999回執(zhí)喔”,”MT9999″)); //…… return receiptList; }}

      復(fù)制

      傳統(tǒng)做法-if-else分支

      List receiptList = ReceiptBuilder.generateReceiptList();//循環(huán)處理for (Receipt receipt : receiptList) { if (StringUtils.equals(“MT2101”,receipt.getType())) { System.out.println(“接收到MT2101回執(zhí)”); System.out.println(“解析回執(zhí)內(nèi)容”); System.out.println(“執(zhí)行業(yè)務(wù)邏輯”); } else if (StringUtils.equals(“MT1101”,receipt.getType())) { System.out.println(“接收到MT1101回執(zhí)”); System.out.println(“解析回執(zhí)內(nèi)容”); System.out.println(“執(zhí)行業(yè)務(wù)邏輯”); } else if (StringUtils.equals(“MT8104”,receipt.getType())) { System.out.println(“接收到MT8104回執(zhí)”); System.out.println(“解析回執(zhí)內(nèi)容”); System.out.println(“執(zhí)行業(yè)務(wù)邏輯”); } else if (StringUtils.equals(“MT9999”,receipt.getType())) { System.out.println(“接收到MT9999回執(zhí)”); System.out.println(“解析回執(zhí)內(nèi)容”); System.out.println(“執(zhí)行業(yè)務(wù)邏輯”); System.out.println(“推送郵件”); } // ……未來可能還有好多個else if}

      在遇到if-else的分支業(yè)務(wù)邏輯比較復(fù)雜時,我們都習(xí)慣于將其抽出一個方法或者封裝成一個對象去調(diào)用,這樣整個if-else結(jié)構(gòu)就不會顯得太臃腫。

      就上面例子,當(dāng)回執(zhí)的類型越來越多時,分支else if 就會越來越多,每增加一個回執(zhí)類型,就需要修改或添加if-else分支,違反了開閉原則(對擴(kuò)展開放,對修改關(guān)閉)

      策略模式+Map字典

      我們知道, 策略模式的目的是封裝一系列的算法,它們具有共性,可以相互替換,也就是說讓算法獨(dú)立于使用它的客戶端而獨(dú)立變化,客戶端僅僅依賴于策略接口 。

      在上述場景中,我們可以把if-else分支的業(yè)務(wù)邏輯抽取為各種策略,但是不可避免的是依然需要客戶端寫一些if-else進(jìn)行策略選擇的邏輯,我們可以將這段邏輯抽取到工廠類中去,這就是策略模式+簡單工廠,代碼如下

      策略接口

      /** * @Description: 回執(zhí)處理策略接口 * @Auther: wuzhazha */public interface IReceiptHandleStrategy { void handleReceipt(Receipt receipt);}

      策略接口實(shí)現(xiàn)類,也就是具體的處理者

      public class Mt2101ReceiptHandleStrategy implements IReceiptHandleStrategy { @Override public void handleReceipt(Receipt receipt) { System.out.println(“解析報(bào)文MT2101:” + receipt.getMessage()); }}public class Mt1101ReceiptHandleStrategy implements IReceiptHandleStrategy { @Override public void handleReceipt(Receipt receipt) { System.out.println(“解析報(bào)文MT1101:” + receipt.getMessage()); }}public class Mt8104ReceiptHandleStrategy implements IReceiptHandleStrategy { @Override public void handleReceipt(Receipt receipt) { System.out.println(“解析報(bào)文MT8104:” + receipt.getMessage()); }}public class Mt9999ReceiptHandleStrategy implements IReceiptHandleStrategy { @Override public void handleReceipt(Receipt receipt) { System.out.println(“解析報(bào)文MT9999:” + receipt.getMessage()); }}

      策略上下文類(策略接口的持有者)

      /** * @Description: 上下文類,持有策略接口 * @Auther: wuzhazha */public class ReceiptStrategyContext { private IReceiptHandleStrategy receiptHandleStrategy; /** * 設(shè)置策略接口 * @param receiptHandleStrategy */ public void setReceiptHandleStrategy(IReceiptHandleStrategy receiptHandleStrategy) { this.receiptHandleStrategy = receiptHandleStrategy; } public void handleReceipt(Receipt receipt){ if (receiptHandleStrategy != null) { receiptHandleStrategy.handleReceipt(receipt); } }}

      策略工廠

      /** * @Description: 策略工廠 * @Auther: wuzhazha */public class ReceiptHandleStrategyFactory { private ReceiptHandleStrategyFactory(){} public static IReceiptHandleStrategy getReceiptHandleStrategy(String receiptType){ IReceiptHandleStrategy receiptHandleStrategy = null; if (StringUtils.equals(“MT2101”,receiptType)) { receiptHandleStrategy = new Mt2101ReceiptHandleStrategy(); } else if (StringUtils.equals(“MT8104”,receiptType)) { receiptHandleStrategy = new Mt8104ReceiptHandleStrategy(); } return receiptHandleStrategy; }}

      客戶端

      public class Client { public static void main(String[] args) { //模擬回執(zhí) List receiptList = ReceiptBuilder.generateReceiptList(); //策略上下文 ReceiptStrategyContext receiptStrategyContext = new ReceiptStrategyContext(); for (Receipt receipt : receiptList) { //獲取并設(shè)置策略 IReceiptHandleStrategy receiptHandleStrategy = ReceiptHandleStrategyFactory.getReceiptHandleStrategy(receipt.getType()); receiptStrategyContext.setReceiptHandleStrategy(receiptHandleStrategy); //執(zhí)行策略 receiptStrategyContext.handleReceipt(receipt); } }}

      解析報(bào)文MT2101:我是MT2101回執(zhí)報(bào)文喔 解析報(bào)文MT8104:我是MT8104回執(zhí)報(bào)文喔

      由于我們的目的是消除if-else,那么這里需要將ReceiptHandleStrategyFactory策略工廠進(jìn)行改造下,采用字典的方式存放我的策略,而Map具備key-value結(jié)構(gòu),采用Map是個不錯選擇。

      稍微改造下,代碼如下

      /** * @Description: 策略工廠 * @Auther: wuzhazha */public class ReceiptHandleStrategyFactory { private static Map receiptHandleStrategyMap; private ReceiptHandleStrategyFactory(){ this.receiptHandleStrategyMap = new HashMap(); this.receiptHandleStrategyMap.put(“MT2101”,new Mt2101ReceiptHandleStrategy()); this.receiptHandleStrategyMap.put(“MT8104”,new Mt8104ReceiptHandleStrategy()); } public static IReceiptHandleStrategy getReceiptHandleStrategy(String receiptType){ return receiptHandleStrategyMap.get(receiptType); }}

      經(jīng)過對策略模式+簡單工廠方案的改造,我們已經(jīng)消除了if-else的結(jié)構(gòu),每當(dāng)新來了一種回執(zhí),只需要添加新的回執(zhí)處理策略,并修改ReceiptHandleStrategyFactory中的Map集合。

      如果要使得程序符合開閉原則,則需要調(diào)整ReceiptHandleStrategyFactory中處理策略的獲取方式,通過反射的方式,獲取指定包下的所有IReceiptHandleStrategy實(shí)現(xiàn)類,然后放到字典Map中去。

      責(zé)任鏈模式

      責(zé)任鏈模式是一種對象的行為模式。在責(zé)任鏈模式里,很多對象由每一個對象對其下家的引用而連接起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。

      發(fā)出這個請求的客戶端并不知道鏈上的哪一個對象最終處理這個請求,這使得系統(tǒng)可以在不影響客戶端的情況下動態(tài)地重新組織和分配責(zé)任

      回執(zhí)處理者接口

      /** * @Description: 抽象回執(zhí)處理者接口 * @Auther: wuzhazha */public interface IReceiptHandler { void handleReceipt(Receipt receipt,IReceiptHandleChain handleChain);}

      責(zé)任鏈接口

      /** * @Description: 責(zé)任鏈接口 * @Auther: wuzhazha */public interface IReceiptHandleChain { void handleReceipt(Receipt receipt);}

      責(zé)任鏈接口實(shí)現(xiàn)類

      /** * @Description: 責(zé)任鏈實(shí)現(xiàn)類 * @Auther: wuzhazha */public class ReceiptHandleChain implements IReceiptHandleChain { //記錄當(dāng)前處理者位置 private int index = 0; //處理者集合 private static List receiptHandlerList; static { //從容器中獲取處理器對象 receiptHandlerList = ReceiptHandlerContainer.getReceiptHandlerList(); } @Override public void handleReceipt(Receipt receipt) { if (receiptHandlerList !=null && receiptHandlerList.size() > 0) { if (index != receiptHandlerList.size()) { IReceiptHandler receiptHandler = receiptHandlerList.get(index++); receiptHandler.handleReceipt(receipt,this); } } }}

      具體回執(zhí)處理者

      public class Mt2101ReceiptHandler implements IReceiptHandler { @Override public void handleReceipt(Receipt receipt, IReceiptHandleChain handleChain) { if (StringUtils.equals(“MT2101”,receipt.getType())) { System.out.println(“解析報(bào)文MT2101:” + receipt.getMessage()); } //處理不了該回執(zhí)就往下傳遞 else { handleChain.handleReceipt(receipt); } }}public class Mt8104ReceiptHandler implements IReceiptHandler { @Override public void handleReceipt(Receipt receipt, IReceiptHandleChain handleChain) { if (StringUtils.equals(“MT8104”,receipt.getType())) { System.out.println(“解析報(bào)文MT8104:” + receipt.getMessage()); } //處理不了該回執(zhí)就往下傳遞 else { handleChain.handleReceipt(receipt); } }}

      責(zé)任鏈處理者容器(如果采用spring,則可以通過依賴注入的方式獲取到IReceiptHandler的子類對象)

      /** * @Description: 處理者容器 * @Auther: wuzhazha */public class ReceiptHandlerContainer { private ReceiptHandlerContainer(){} public static List getReceiptHandlerList(){ List receiptHandlerList = new ArrayList(); receiptHandlerList.add(new Mt2101ReceiptHandler()); receiptHandlerList.add(new Mt8104ReceiptHandler()); return receiptHandlerList; }}

      客戶端

      public class Client { public static void main(String[] args) { //模擬回執(zhí) List receiptList = ReceiptBuilder.generateReceiptList(); for (Receipt receipt : receiptList) { //回執(zhí)處理鏈對象 ReceiptHandleChain receiptHandleChain = new ReceiptHandleChain(); receiptHandleChain.handleReceipt(receipt); } }}

      解析報(bào)文MT2101:我是MT2101回執(zhí)報(bào)文喔 解析報(bào)文MT8104:我是MT8104回執(zhí)報(bào)文喔

      通過責(zé)任鏈的處理方式,if-else結(jié)構(gòu)也被我們消除了,每當(dāng)新來了一種回執(zhí),只需要添加IReceiptHandler實(shí)現(xiàn)類并修改ReceiptHandlerContainer處理者容器即可,如果要使得程序符合開閉原則,則需要調(diào)整ReceiptHandlerContainer中處理者的獲取方式,通過反射的方式,獲取指定包下的所有IReceiptHandler實(shí)現(xiàn)類。Java知音公眾號內(nèi)回復(fù)“后端面試”,送你一份面試寶典

      這里使用到了一個反射工具類,用于獲取指定接口的所有實(shí)現(xiàn)類

      /** * @Description: 反射工具類 * @Auther: wuzhazha */public class ReflectionUtil { /** * 定義類集合(用于存放所有加載的類) */ private static final Set CLASS_SET; static { //指定加載包路徑 CLASS_SET = getClassSet(“com.yaolong”); } /** * 獲取類加載器 * @return */ public static ClassLoader getClassLoader(){ return Thread.currentThread().getContextClassLoader(); } /** * 加載類 * @param className 類全限定名稱 * @param isInitialized 是否在加載完成后執(zhí)行靜態(tài)代碼塊 * @return */ public static Class loadClass(String className,boolean isInitialized) { Class cls; try { cls = Class.forName(className,isInitialized,getClassLoader()); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } return cls; } public static Class loadClass(String className) { return loadClass(className,true); } /** * 獲取指定包下所有類 * @param packageName * @return */ public static Set getClassSet(String packageName) { Set classSet = new HashSet(); try { Enumeration urls = getClassLoader().getResources(packageName.replace(“.”,”/”)); while (urls.hasMoreElements()) { URL url = urls.nextElement(); if (url != null) { String protocol = url.getProtocol(); if (protocol.equals(“file”)) { String packagePath = url.getPath().replace(“%20″,””); addClass(classSet,packagePath,packageName); } else if (protocol.equals(“jar”)) { JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection(); if (jarURLConnection != null) { JarFile jarFile = jarURLConnection.getJarFile(); if (jarFile != null) { Enumeration jarEntries = jarFile.entries(); while (jarEntries.hasMoreElements()) { JarEntry jarEntry = jarEntries.nextElement(); String jarEntryName = jarEntry.getName(); if (jarEntryName.endsWith(“.class”)) { String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(“.”)).replaceAll(“/”, “.”); doAddClass(classSet,className); } } } } } } } } catch (IOException e) { throw new RuntimeException(e); } return classSet; } private static void doAddClass(Set classSet, String className) { Class cls = loadClass(className,false); classSet.add(cls); } private static void addClass(Set classSet, String packagePath, String packageName) { final File[] files = new File(packagePath).listFiles(new FileFilter() { @Override public boolean accept(File file) { return (file.isFile() && file.getName().endsWith(“.class”)) || file.isDirectory(); } }); for (File file : files) { String fileName = file.getName(); if (file.isFile()) { String className = fileName.substring(0, fileName.lastIndexOf(“.”)); if (StringUtils.isNotEmpty(packageName)) { className = packageName + “.” + className; } doAddClass(classSet,className); } else { String subPackagePath = fileName; if (StringUtils.isNotEmpty(packagePath)) { subPackagePath = packagePath + “/” + subPackagePath; } String subPackageName = fileName; if (StringUtils.isNotEmpty(packageName)) { subPackageName = packageName + “.” + subPackageName; } addClass(classSet,subPackagePath,subPackageName); } } } public static Set getClassSet() { return CLASS_SET; } /** * 獲取應(yīng)用包名下某父類(或接口)的所有子類(或?qū)崿F(xiàn)類) * @param superClass * @return */ public static Set getClassSetBySuper(Class superClass) { Set classSet = new HashSet(); for (Class cls : CLASS_SET) { if (superClass.isAssignableFrom(cls) && !superClass.equals(cls)) { classSet.add(cls); } } return classSet; } /** * 獲取應(yīng)用包名下帶有某注解的類 * @param annotationClass * @return */ public static Set getClassSetByAnnotation(Class annotationClass) { Set classSet = new HashSet(); for (Class cls : CLASS_SET) { if (cls.isAnnotationPresent(annotationClass)) { classSet.add(cls); } } return classSet; }}

      接下來改造ReceiptHandlerContainer

      public class ReceiptHandlerContainer { private ReceiptHandlerContainer(){} public static List getReceiptHandlerList(){ List receiptHandlerList = new ArrayList(); //獲取IReceiptHandler接口的實(shí)現(xiàn)類 Set classList = ReflectionUtil.getClassSetBySuper(IReceiptHandler.class); if (classList != null && classList.size() > 0) { for (Class clazz : classList) { try { receiptHandlerList.add((IReceiptHandler)clazz.newInstance()); } catch ( Exception e) { e.printStackTrace(); } } } return receiptHandlerList; }}

      至此,該方案完美符合了開閉原則,如果新增一個回執(zhí)類型,只需要添加一個新的回執(zhí)處理器即可,無需做其它改動。如新加了MT6666的回執(zhí),代碼如下

      public class Mt6666ReceiptHandler implements IReceiptHandler { @Override public void handleReceipt(Receipt receipt, IReceiptHandleChain handleChain) { if (StringUtils.equals(“MT6666”,receipt.getType())) { System.out.println(“解析報(bào)文MT6666:” + receipt.getMessage()); } //處理不了該回執(zhí)就往下傳遞 else { handleChain.handleReceipt(receipt); } }}

      策略模式+注解

      此方案其實(shí)和上述沒有太大異同,為了能符合開閉原則,通過自定義注解的方式,標(biāo)記處理者類,然后反射獲取到該類集合,放到Map容器中,這里不再贅述

      小結(jié)

      if-else或switch case 這種分支判斷的方式對于分支邏輯不多的簡單業(yè)務(wù),還是直觀高效的。對于業(yè)務(wù)復(fù)雜,分支邏輯多,采用適當(dāng)?shù)哪J郊记?,會讓代碼更加清晰,容易維護(hù),但同時類或方法數(shù)量也是倍增的。我們需要對業(yè)務(wù)做好充分分析,避免一上來就設(shè)計(jì)模式,避免過度設(shè)計(jì)!

      鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場,版權(quán)歸原作者所有,如有侵權(quán)請聯(lián)系管理員(admin#wlmqw.com)刪除。
      用戶投稿
      上一篇 2022年6月21日 06:40
      下一篇 2022年6月21日 06:40

      相關(guān)推薦

      聯(lián)系我們

      聯(lián)系郵箱:admin#wlmqw.com
      工作時間:周一至周五,10:30-18:30,節(jié)假日休息