精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

實戰(zhàn)!工作中常用到哪些設(shè)計模式

開發(fā) 前端
假設(shè)你跟不同性格類型的小姐姐約會,要用不同的策略,有的請電影比較好,有的則去吃小吃效果不錯,有的去逛街買買買最合適。當(dāng)然,目的都是為了得到小姐姐的芳心,請看電影、吃小吃、逛街就是不同的策略。

[[431423]]

前言

大家好,我是撿田螺的小男孩。

平時我們寫代碼呢,多數(shù)情況都是流水線式寫代碼,基本就可以實現(xiàn)業(yè)務(wù)邏輯了。如何在寫代碼中找到樂趣呢,我覺得,最好的方式就是:使用設(shè)計模式優(yōu)化自己的業(yè)務(wù)代碼。今天跟大家聊聊日常工作中,我都使用過哪些設(shè)計模式。

工作中常用到哪些設(shè)計模式

1.策略模式

1.1 業(yè)務(wù)場景

假設(shè)有這樣的業(yè)務(wù)場景,大數(shù)據(jù)系統(tǒng)把文件推送過來,根據(jù)不同類型采取不同的解析方式。多數(shù)的小伙伴就會寫出以下的代碼:

  1. if(type=="A"){ 
  2.    //按照A格式解析 
  3.   
  4. }else if(type=="B"){ 
  5.     //按B格式解析 
  6. }else
  7.     //按照默認(rèn)格式解析 

 這個代碼可能會存在哪些問題呢?

  • 如果分支變多,這里的代碼就會變得臃腫,難以維護(hù),可讀性低。
  • 如果你需要接入一種新的解析類型,那只能在原有代碼上修改。

說得專業(yè)一點的話,就是以上代碼,違背了面向?qū)ο缶幊痰拈_閉原則以及單一原則。

  • 開閉原則(對于擴展是開放的,但是對于修改是封閉的):增加或者刪除某個邏輯,都需要修改到原來代碼
  • 單一原則(規(guī)定一個類應(yīng)該只有一個發(fā)生變化的原因):修改任何類型的分支邏輯代碼,都需要改動當(dāng)前類的代碼。

如果你的代碼就是醬紫:有多個if...else等條件分支,并且每個條件分支,可以封裝起來替換的,我們就可以使用策略模式來優(yōu)化。

1.2 策略模式定義

策略模式定義了算法族,分別封裝起來,讓它們之間可以相互替換,此模式讓算法的變化獨立于使用算法的的客戶。這個策略模式的定義是不是有點抽象呢?那我們來看點通俗易懂的比喻:

假設(shè)你跟不同性格類型的小姐姐約會,要用不同的策略,有的請電影比較好,有的則去吃小吃效果不錯,有的去逛街買買買最合適。當(dāng)然,目的都是為了得到小姐姐的芳心,請看電影、吃小吃、逛街就是不同的策略。

策略模式針對一組算法,將每一個算法封裝到具有共同接口的獨立的類中,從而使得它們可以相互替換。

1.3 策略模式使用

策略模式怎么使用呢?醬紫實現(xiàn)的:

一個接口或者抽象類,里面兩個方法(一個方法匹配類型,一個可替換的邏輯實現(xiàn)方法)

不同策略的差異化實現(xiàn)(就是說,不同策略的實現(xiàn)類)

使用策略模式

1.3.1 一個接口,兩個方法

  1. public interface IFileStrategy { 
  2.      
  3.     //屬于哪種文件解析類型 
  4.     FileTypeResolveEnum gainFileType(); 
  5.      
  6.     //封裝的公用算法(具體的解析方法) 
  7.     void resolve(Object objectparam); 

 1.3.2 不同策略的差異化實現(xiàn)

A 類型策略具體實現(xiàn)

  1. @Component 
  2. public class AFileResolve implements IFileStrategy { 
  3.      
  4.     @Override 
  5.     public FileTypeResolveEnum gainFileType() { 
  6.         return FileTypeResolveEnum.File_A_RESOLVE; 
  7.     } 
  8.  
  9.     @Override 
  10.     public void resolve(Object objectparam) { 
  11.       logger.info("A 類型解析文件,參數(shù):{}",objectparam); 
  12.       //A類型解析具體邏輯 
  13.     } 

 B 類型策略具體實現(xiàn)

  1. @Component 
  2. public class BFileResolve implements IFileStrategy { 
  3.     
  4.     @Override 
  5.     public FileTypeResolveEnum gainFileType() { 
  6.         return FileTypeResolveEnum.File_B_RESOLVE; 
  7.     } 
  8.  
  9.  
  10.     @Override 
  11.     public void resolve(Object objectparam) { 
  12.       logger.info("B 類型解析文件,參數(shù):{}",objectparam); 
  13.       //B類型解析具體邏輯 
  14.     } 

默認(rèn)類型策略具體實現(xiàn)

  1. @Component 
  2. public class DefaultFileResolve implements IFileStrategy { 
  3.  
  4.     @Override 
  5.     public FileTypeResolveEnum gainFileType() { 
  6.         return FileTypeResolveEnum.File_DEFAULT_RESOLVE; 
  7.     } 
  8.  
  9.     @Override 
  10.     public void resolve(Object objectparam) { 
  11.       logger.info("默認(rèn)類型解析文件,參數(shù):{}",objectparam); 
  12.       //默認(rèn)類型解析具體邏輯 
  13.     } 

 1.3.3 使用策略模式

如何使用呢?我們借助spring的生命周期,使用ApplicationContextAware接口,把對用的策略,初始化到map里面。然后對外提供resolveFile方法即可。

  1. /** 
  2.  *  @author 公眾號:撿田螺的小男孩 
  3.  */ 
  4. @Component 
  5. public class StrategyUseService implements ApplicationContextAware{ 
  6.  
  7.    
  8.     private Map<FileTypeResolveEnum, IFileStrategy> iFileStrategyMap = new ConcurrentHashMap<>(); 
  9.  
  10.     public void resolveFile(FileTypeResolveEnum fileTypeResolveEnum, Object objectParam) { 
  11.         IFileStrategy iFileStrategy = iFileStrategyMap.get(fileTypeResolveEnum); 
  12.         if (iFileStrategy != null) { 
  13.             iFileStrategy.resolve(objectParam); 
  14.         } 
  15.     } 
  16.  
  17.     //把不同策略放到map 
  18.     @Override 
  19.     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
  20.         Map<String, IFileStrategy> tmepMap = applicationContext.getBeansOfType(IFileStrategy.class); 
  21.         tmepMap.values().forEach(strategyService -> iFileStrategyMap.put(strategyService.gainFileType(), strategyService)); 
  22.     } 

2. 責(zé)任鏈模式

2.1 業(yè)務(wù)場景

我們來看一個常見的業(yè)務(wù)場景,下訂單。下訂單接口,基本的邏輯,一般有參數(shù)非空校驗、安全校驗、黑名單校驗、規(guī)則攔截等等。很多伙伴會使用異常來實現(xiàn):

  1. public class Order { 
  2.  
  3.     public void checkNullParam(Object param){ 
  4.       //參數(shù)非空校驗 
  5.       throw new RuntimeException(); 
  6.     } 
  7.     public void checkSecurity(){ 
  8.       //安全校驗 
  9.       throw new RuntimeException(); 
  10.     } 
  11.     public void checkBackList(){ 
  12.         //黑名單校驗 
  13.         throw new RuntimeException(); 
  14.     } 
  15.     public void checkRule(){ 
  16.         //規(guī)則攔截 
  17.         throw new RuntimeException(); 
  18.     } 
  19.  
  20.     public static void main(String[] args) { 
  21.         Order order= new Order(); 
  22.         try{ 
  23.             order.checkNullParam(); 
  24.             order.checkSecurity (); 
  25.             order.checkBackList(); 
  26.             order2.checkRule(); 
  27.             System.out.println("order success"); 
  28.         }catch (RuntimeException e){ 
  29.             System.out.println("order fail"); 
  30.         } 
  31.     } 

 這段代碼使用了異常來做邏輯條件判斷,如果后續(xù)邏輯越來越復(fù)雜的話,會出現(xiàn)一些問題:如異常只能返回異常信息,不能返回更多的字段,這時候需要自定義異常類。

并且,阿里開發(fā)手冊規(guī)定:禁止用異常做邏輯判斷。

【強制】 異常不要用來做流程控制,條件控制。說明:異常設(shè)計的初衷是解決程序運行中的各種意外情況,且異常的處理效率比條件判斷方式要低很多。

如何優(yōu)化這段代碼呢?可以考慮責(zé)任鏈模式

2.2 責(zé)任鏈模式定義

當(dāng)你想要讓一個以上的對象有機會能夠處理某個請求的時候,就使用責(zé)任鏈模式。

責(zé)任鏈模式為請求創(chuàng)建了一個接收者對象的鏈。執(zhí)行鏈上有多個對象節(jié)點,每個對象節(jié)點都有機會(條件匹配)處理請求事務(wù),如果某個對象節(jié)點處理完了,就可以根據(jù)實際業(yè)務(wù)需求傳遞給下一個節(jié)點繼續(xù)處理或者返回處理完畢。這種模式給予請求的類型,對請求的發(fā)送者和接收者進(jìn)行解耦。

責(zé)任鏈模式實際上是一種處理請求的模式,它讓多個處理器(對象節(jié)點)都有機會處理該請求,直到其中某個處理成功為止。責(zé)任鏈模式把多個處理器串成鏈,然后讓請求在鏈上傳遞:

責(zé)任鏈模式

打個比喻:

假設(shè)你晚上去上選修課,為了可以走點走,坐到了最后一排。來到教室,發(fā)現(xiàn)前面坐了好幾個漂亮的小姐姐,于是你找張紙條,寫上:“你好, 可以做我的女朋友嗎?如果不愿意請向前傳”。紙條就一個接一個的傳上去了,后來傳到第一排的那個妹子手上,她把紙條交給老師,聽說老師40多歲未婚...

2.3 責(zé)任鏈模式使用

責(zé)任鏈模式怎么使用呢?

  • 一個接口或者抽象類
  • 每個對象差異化處理
  • 對象鏈(數(shù)組)初始化(連起來)

2.3.1 一個接口或者抽象類

這個接口或者抽象類,需要:

  • 有一個指向責(zé)任下一個對象的屬性
  • 一個設(shè)置下一個對象的set方法
  • 給子類對象差異化實現(xiàn)的方法(如以下代碼的doFilter方法)
  1. /** 
  2.  *  關(guān)注公眾號:撿田螺的小男孩 
  3.  */ 
  4. public abstract class AbstractHandler { 
  5.  
  6.     //責(zé)任鏈中的下一個對象 
  7.     private AbstractHandler nextHandler; 
  8.  
  9.     /** 
  10.      * 責(zé)任鏈的下一個對象 
  11.      */ 
  12.     public void setNextHandler(AbstractHandler nextHandler){ 
  13.         this.nextHandler = nextHandler; 
  14.     } 
  15.  
  16.     /** 
  17.      * 具體參數(shù)攔截邏輯,給子類去實現(xiàn) 
  18.      */ 
  19.     public void filter(Request request, Response response) { 
  20.         doFilter(request, response); 
  21.         if (getNextHandler() != null) { 
  22.             getNextHandler().filter(request, response); 
  23.         } 
  24.     } 
  25.  
  26.     public AbstractHandler getNextHandler() { 
  27.         return nextHandler; 
  28.     } 
  29.  
  30.      abstract void doFilter(Request filterRequest, Response response); 
  31.  

2.3.2 每個對象差異化處理

責(zé)任鏈上,每個對象的差異化處理,如本小節(jié)的業(yè)務(wù)場景,就有參數(shù)校驗對象、安全校驗對象、黑名單校驗對象、規(guī)則攔截對象

  1. /** 
  2.  * 參數(shù)校驗對象 
  3.  **/ 
  4. @Component 
  5. @Order(1) //順序排第1,最先校驗 
  6. public class CheckParamFilterObject extends AbstractHandler { 
  7.  
  8.     @Override 
  9.     public void doFilter(Request request, Response response) { 
  10.         System.out.println("非空參數(shù)檢查"); 
  11.     } 
  12.  
  13. /** 
  14.  *  安全校驗對象 
  15.  */ 
  16. @Component 
  17. @Order(2) //校驗順序排第2 
  18. public class CheckSecurityFilterObject extends AbstractHandler { 
  19.  
  20.     @Override 
  21.     public void doFilter(Request request, Response response) { 
  22.         //invoke Security check 
  23.         System.out.println("安全調(diào)用校驗"); 
  24.     } 
  25. /** 
  26.  *  黑名單校驗對象 
  27.  */ 
  28. @Component 
  29. @Order(3) //校驗順序排第3 
  30. public class CheckBlackFilterObject extends AbstractHandler { 
  31.  
  32.     @Override 
  33.     public void doFilter(Request request, Response response) { 
  34.         //invoke black list check 
  35.         System.out.println("校驗黑名單"); 
  36.     } 
  37.  
  38. /** 
  39.  *  規(guī)則攔截對象 
  40.  */ 
  41. @Component 
  42. @Order(4) //校驗順序排第4 
  43. public class CheckRuleFilterObject extends AbstractHandler { 
  44.  
  45.     @Override 
  46.     public void doFilter(Request request, Response response) { 
  47.         //check rule 
  48.         System.out.println("check rule"); 
  49.     } 

 2.3.3 對象鏈連起來(初始化)&& 使用

  1. @Component("ChainPatternDemo"
  2. public class ChainPatternDemo { 
  3.  
  4.     //自動注入各個責(zé)任鏈的對象 
  5.     @Autowired 
  6.     private List<AbstractHandler> abstractHandleList; 
  7.  
  8.     private AbstractHandler abstractHandler; 
  9.  
  10.     //spring注入后自動執(zhí)行,責(zé)任鏈的對象連接起來 
  11.     @PostConstruct 
  12.     public void initializeChainFilter(){ 
  13.  
  14.         for(int i = 0;i<abstractHandleList.size();i++){ 
  15.             if(i == 0){ 
  16.                 abstractHandler = abstractHandleList.get(0); 
  17.             }else
  18.                 AbstractHandler currentHander = abstractHandleList.get(i - 1); 
  19.                 AbstractHandler nextHander = abstractHandleList.get(i); 
  20.                 currentHander.setNextHandler(nextHander); 
  21.             } 
  22.         } 
  23.     } 
  24.  
  25.     //直接調(diào)用這個方法使用 
  26.     public Response exec(Request request, Response response) { 
  27.         abstractHandler.filter(request, response); 
  28.         return response; 
  29.     } 
  30.  
  31.     public AbstractHandler getAbstractHandler() { 
  32.         return abstractHandler; 
  33.     } 
  34.  
  35.     public void setAbstractHandler(AbstractHandler abstractHandler) { 
  36.         this.abstractHandler = abstractHandler; 
  37.     } 

運行結(jié)果如下:

  1. 非空參數(shù)檢查 
  2. 安全調(diào)用校驗 
  3. 校驗黑名單 
  4. check rule 

 3. 模板方法模式

3.1 業(yè)務(wù)場景

假設(shè)我們有這么一個業(yè)務(wù)場景:內(nèi)部系統(tǒng)不同商戶,調(diào)用我們系統(tǒng)接口,去跟外部第三方系統(tǒng)交互(http方式)。走類似這么一個流程,如下:

一個請求都會經(jīng)歷這幾個流程:

  • 查詢商戶信息
  • 對請求報文加簽
  • 發(fā)送http請求出去
  • 對返回的報文驗簽

這里,有的商戶可能是走代理出去的,有的是走直連。假設(shè)當(dāng)前有A,B商戶接入,不少伙伴可能這么實現(xiàn),偽代碼如下:

  1. // 商戶A處理句柄 
  2. CompanyAHandler implements RequestHandler { 
  3.    Resp hander(req){ 
  4.    //查詢商戶信息 
  5.    queryMerchantInfo(); 
  6.    //加簽 
  7.    signature(); 
  8.    //http請求(A商戶假設(shè)走的是代理) 
  9.    httpRequestbyProxy() 
  10.    //驗簽 
  11.    verify(); 
  12.    } 
  13. // 商戶B處理句柄 
  14. CompanyBHandler implements RequestHandler { 
  15.    Resp hander(Rreq){ 
  16.    //查詢商戶信息 
  17.    queryMerchantInfo(); 
  18.    //加簽 
  19.    signature(); 
  20.    // http請求(B商戶不走代理,直連) 
  21.    httpRequestbyDirect(); 
  22.    // 驗簽 
  23.    verify();  
  24.    } 

 假設(shè)新加一個C商戶接入,你需要再實現(xiàn)一套這樣的代碼。顯然,這樣代碼就重復(fù)了,一些通用的方法,卻在每一個子類都重新寫了這一方法。

如何優(yōu)化呢?可以使用模板方法模式。

3.2 模板方法模式定義

定義一個操作中的算法的骨架流程,而將一些步驟延遲到子類中,使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。它的核心思想就是:定義一個操作的一系列步驟,對于某些暫時確定不下來的步驟,就留給子類去實現(xiàn),這樣不同的子類就可以定義出不同的步驟。

打個通俗的比喻:

模式舉例:追女朋友要先“牽手”,再“擁抱”,再“接吻”, 再“拍拍..額..手”。至于具體你用左手還是右手牽,無所謂,但是整個過程,定了一個流程模板,按照模板來就行。

3.3 模板方法使用

  • 一個抽象類,定義骨架流程(抽象方法放一起)
  • 確定的共同方法步驟,放到抽象類(去除抽象方法標(biāo)記)
  • 不確定的步驟,給子類去差異化實現(xiàn)

我們繼續(xù)那以上的舉例的業(yè)務(wù)流程例子,來一起用 模板方法優(yōu)化一下哈:

3.3.1 一個抽象類,定義骨架流程

因為一個個請求經(jīng)過的流程為一下步驟:

  • 查詢商戶信息
  • 對請求報文加簽
  • 發(fā)送http請求出去
  • 對返回的報文驗簽

所以我們就可以定義一個抽象類,包含請求流程的幾個方法,方法首先都定義為抽象方法哈:

  1. /** 
  2.  * 抽象類定義骨架流程(查詢商戶信息,加簽,http請求,驗簽) 
  3.  */ 
  4. abstract class AbstractMerchantService  {  
  5.  
  6.       //查詢商戶信息 
  7.       abstract queryMerchantInfo(); 
  8.       //加簽 
  9.       abstract signature(); 
  10.       //http 請求 
  11.       abstract httpRequest(); 
  12.        // 驗簽 
  13.        abstract verifySinature(); 
  14.   

 3.3.2 確定的共同方法步驟,放到抽象類

  1. abstract class AbstractMerchantService  {  
  2.  
  3.      //模板方法流程 
  4.      Resp handlerTempPlate(req){ 
  5.            //查詢商戶信息 
  6.            queryMerchantInfo(); 
  7.            //加簽 
  8.            signature(); 
  9.            //http 請求 
  10.            httpRequest(); 
  11.            // 驗簽 
  12.            verifySinature(); 
  13.      } 
  14.       // Http是否走代理(提供給子類實現(xiàn)) 
  15.       abstract boolean isRequestByProxy(); 

 3.3.3 不確定的步驟,給子類去差異化實現(xiàn)

因為是否走代理流程是不確定的,所以給子類去實現(xiàn)。

商戶A的請求實現(xiàn):

  1. CompanyAServiceImpl extends AbstractMerchantService{ 
  2.     Resp hander(req){ 
  3.       return handlerTempPlate(req); 
  4.     } 
  5.     //走h(yuǎn)ttp代理的 
  6.     boolean isRequestByProxy(){ 
  7.        return true
  8.     } 

 商戶B的請求實現(xiàn):

  1. CompanyBServiceImpl extends AbstractMerchantService{ 
  2.     Resp hander(req){ 
  3.       return handlerTempPlate(req); 
  4.     } 
  5.     //公司B是不走代理的 
  6.     boolean isRequestByProxy(){ 
  7.        return false
  8.     } 

 4. 觀察者模式

4.1 業(yè)務(wù)場景

登陸注冊應(yīng)該是最常見的業(yè)務(wù)場景了。就拿注冊來說事,我們經(jīng)常會遇到類似的場景,就是用戶注冊成功后,我們給用戶發(fā)一條消息,又或者發(fā)個郵件等等,因此經(jīng)常有如下的代碼:

  1. void register(User user){ 
  2.   insertRegisterUser(user); 
  3.   sendIMMessage(); 
  4.   sendEmail(); 

 這塊代碼會有什么問題呢?如果產(chǎn)品又加需求:現(xiàn)在注冊成功的用戶,再給用戶發(fā)一條短信通知。于是你又得改register方法的代碼了。。。這是不是違反了開閉原則啦。

  1. void register(User user){ 
  2.   insertRegisterUser(user); 
  3.   sendIMMessage(); 
  4.   sendMobileMessage(); 
  5.   sendEmail(); 

 并且,如果調(diào)發(fā)短信的接口失敗了,是不是又影響到用戶注冊了?!這時候,是不是得加個異步方法給通知消息才好。。。

實際上,我們可以使用觀察者模式優(yōu)化。

4.2 觀察者模式定義

觀察者模式定義對象間的一種一對多的依賴關(guān)系,當(dāng)一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并被完成業(yè)務(wù)的更新。

觀察者模式屬于行為模式,一個對象(被觀察者)的狀態(tài)發(fā)生改變,所有的依賴對象(觀察者對象)都將得到通知,進(jìn)行廣播通知。它的主要成員就是觀察者和被觀察者。

被觀察者(Observerable):目標(biāo)對象,狀態(tài)發(fā)生變化時,將通知所有的觀察者。

觀察者(observer):接受被觀察者的狀態(tài)變化通知,執(zhí)行預(yù)先定義的業(yè)務(wù)。

使用場景: 完成某件事情后,異步通知場景。如,登陸成功,發(fā)個IM消息等等。

4.3 觀察者模式使用

觀察者模式實現(xiàn)的話,還是比較簡單的。

  • 一個被觀察者的類Observerable ;
  • 多個觀察者Observer ;
  • 觀察者的差異化實現(xiàn)
  • 經(jīng)典觀察者模式封裝:EventBus實戰(zhàn)

4.3.1 一個被觀察者的類Observerable 和 多個觀察者Observer

  1. public class Observerable { 
  2.     
  3.    private List<Observer> observers  
  4.       = new ArrayList<Observer>(); 
  5.    private int state; 
  6.   
  7.    public int getState() { 
  8.       return state; 
  9.    } 
  10.   
  11.    public void setState(int state) { 
  12.       notifyAllObservers(); 
  13.    } 
  14.   
  15.    //添加觀察者 
  16.    public void addServer(Observer observer){ 
  17.       observers.add(observer);       
  18.    } 
  19.     
  20.    //移除觀察者 
  21.    public void removeServer(Observer observer){ 
  22.       observers.remove(observer);       
  23.    } 
  24.    //通知 
  25.    public void notifyAllObservers(int state){ 
  26.       if(state!=1){ 
  27.           System.out.println(“不是通知的狀態(tài)”); 
  28.          return ; 
  29.       } 
  30.     
  31.       for (Observer observer : observers) { 
  32.          observer.doEvent(); 
  33.       } 
  34.    }   

 4.3.2 觀察者的差異化實現(xiàn)

  1. //觀察者 
  2.  interface Observer {   
  3.     void doEvent();   
  4. }   
  5. //Im消息 
  6. IMMessageObserver implements Observer{ 
  7.     void doEvent(){ 
  8.        System.out.println("發(fā)送IM消息"); 
  9.     } 
  10.  
  11. //手機短信 
  12. MobileNoObserver implements Observer{ 
  13.     void doEvent(){ 
  14.        System.out.println("發(fā)送短信消息"); 
  15.     } 
  16. //EmailNo 
  17. EmailObserver implements Observer{ 
  18.     void doEvent(){ 
  19.        System.out.println("發(fā)送email消息"); 
  20.     } 

 4.3.3 EventBus實戰(zhàn)

自己搞一套觀察者模式的代碼,還是有點小麻煩。實際上,Guava EventBus就封裝好了,它 提供一套基于注解的事件總線,api可以靈活的使用,爽歪歪。

我們來看下EventBus的實戰(zhàn)代碼哈,首先可以聲明一個EventBusCenter類,它類似于以上被觀察者那種角色Observerable。

 

  1. public class EventBusCenter { 
  2.  
  3.     private static EventBus eventBus = new EventBus(); 
  4.  
  5.     private EventBusCenter() { 
  6.     } 
  7.  
  8.     public static EventBus getInstance() { 
  9.         return eventBus; 
  10.     } 
  11.      //添加觀察者 
  12.     public static void register(Object obj) { 
  13.         eventBus.register(obj); 
  14.     } 
  15.     //移除觀察者 
  16.     public static void unregister(Object obj) { 
  17.         eventBus.unregister(obj); 
  18.     } 
  19.     //把消息推給觀察者 
  20.     public static void post(Object obj) { 
  21.         eventBus.post(obj); 
  22.     } 

 

然后再聲明觀察者EventListener

 

  1. public class EventListener { 
  2.  
  3.     @Subscribe //加了訂閱,這里標(biāo)記這個方法是事件處理方法   
  4.     public void handle(NotifyEvent notifyEvent) { 
  5.         System.out.println("發(fā)送IM消息" + notifyEvent.getImNo()); 
  6.         System.out.println("發(fā)送短信消息" + notifyEvent.getMobileNo()); 
  7.         System.out.println("發(fā)送Email消息" + notifyEvent.getEmailNo()); 
  8.     } 
  9.  
  10. //通知事件類 
  11. public class NotifyEvent  { 
  12.  
  13.     private String mobileNo; 
  14.  
  15.     private String emailNo; 
  16.  
  17.     private String imNo; 
  18.  
  19.     public NotifyEvent(String mobileNo, String emailNo, String imNo) { 
  20.         this.mobileNo = mobileNo; 
  21.         this.emailNo = emailNo; 
  22.         this.imNo = imNo; 
  23.     } 
  24.  } 

 

使用demo測試:

 

  1. public class EventBusDemoTest { 
  2.  
  3.     public static void main(String[] args) { 
  4.  
  5.         EventListener eventListener = new EventListener(); 
  6.         EventBusCenter.register(eventListener); 
  7.         EventBusCenter.post(new NotifyEvent("13372817283""123@qq.com""666")); 
  8.         } 

 

運行結(jié)果:

 

  1. 發(fā)送IM消息666 
  2. 發(fā)送短信消息13372817283 
  3. 發(fā)送Email消息123@qq.com 

 

5. 工廠模式

5.1 業(yè)務(wù)場景

工廠模式一般配合策略模式一起使用。用來去優(yōu)化大量的if...else...或switch...case...條件語句。

我們就取第一小節(jié)中策略模式那個例子吧。根據(jù)不同的文件解析類型,創(chuàng)建不同的解析對象

 

  1. IFileStrategy getFileStrategy(FileTypeResolveEnum fileType){ 
  2.     IFileStrategy  fileStrategy ; 
  3.     if(fileType=FileTypeResolveEnum.File_A_RESOLVE){ 
  4.       fileStrategy = new AFileResolve(); 
  5.     }else if(fileType=FileTypeResolveEnum.File_A_RESOLV){ 
  6.       fileStrategy = new BFileResolve(); 
  7.     }else
  8.       fileStrategy = new DefaultFileResolve(); 
  9.     } 
  10.     return fileStrategy; 

 

其實這就是工廠模式,定義一個創(chuàng)建對象的接口,讓其子類自己決定實例化哪一個工廠類,工廠模式使其創(chuàng)建過程延遲到子類進(jìn)行。

策略模式的例子,沒有使用上一段代碼,而是借助spring的特性,搞了一個工廠模式,哈哈,小伙伴們可以回去那個例子細(xì)品一下,我把代碼再搬下來,小伙伴們再品一下吧:

 

  1. /** 
  2.  *  @author 公眾號:撿田螺的小男孩 
  3.  */ 
  4. @Component 
  5. public class StrategyUseService implements ApplicationContextAware{ 
  6.  
  7.     private Map<FileTypeResolveEnum, IFileStrategy> iFileStrategyMap = new ConcurrentHashMap<>(); 
  8.  
  9.     //把所有的文件類型解析的對象,放到map,需要使用時,信手拈來即可。這就是工廠模式的一種體現(xiàn)啦 
  10.     @Override 
  11.     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
  12.         Map<String, IFileStrategy> tmepMap = applicationContext.getBeansOfType(IFileStrategy.class); 
  13.         tmepMap.values().forEach(strategyService -> iFileStrategyMap.put(strategyService.gainFileType(), strategyService)); 
  14.     } 

 

5.2 使用工廠模式

定義工廠模式也是比較簡單的:

一個工廠接口,提供一個創(chuàng)建不同對象的方法。

其子類實現(xiàn)工廠接口,構(gòu)造不同對象

使用工廠模式

5.3.1 一個工廠接口

 

  1. interface IFileResolveFactory{ 
  2.    void resolve(); 

 

5.3.2 不同子類實現(xiàn)工廠接口

 

  1. class AFileResolve implements IFileResolveFactory{ 
  2.    void resolve(){ 
  3.       System.out.println("文件A類型解析"); 
  4.    } 
  5.  
  6. class BFileResolve implements IFileResolveFactory{ 
  7.    void resolve(){ 
  8.       System.out.println("文件B類型解析"); 
  9.    } 
  10.  
  11. class DefaultFileResolve implements IFileResolveFactory{ 
  12.    void resolve(){ 
  13.       System.out.println("默認(rèn)文件類型解析"); 
  14.    } 

 

5.3.3 使用工廠模式

 

  1. //構(gòu)造不同的工廠對象 
  2. IFileResolveFactory fileResolveFactory; 
  3. if(fileType=“A”){ 
  4.     fileResolveFactory = new AFileResolve(); 
  5. }else if(fileType=“B”){ 
  6.     fileResolveFactory = new BFileResolve(); 
  7.  }else
  8.     fileResolveFactory = new DefaultFileResolve(); 
  9.  
  10. fileResolveFactory.resolve(); 

 

一般情況下,對于工廠模式,你不會看到以上的代碼。工廠模式會跟配合其他設(shè)計模式如策略模式一起出現(xiàn)的。

6. 單例模式

6.1 業(yè)務(wù)場景

單例模式,保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。I/O與數(shù)據(jù)庫的連接,一般就用單例模式實現(xiàn)de的。Windows里面的Task Manager(任務(wù)管理器)也是很典型的單例模式。

來看一個單例模式的例子

 

  1. /** 
  2.  *  公眾號:撿田螺的小男孩 
  3.  */ 
  4. public class LanHanSingleton { 
  5.  
  6.     private static LanHanSingleton instance; 
  7.  
  8.     private LanHanSingleton(){ 
  9.  
  10.     } 
  11.  
  12.     public static LanHanSingleton getInstance(){ 
  13.         if (instance == null) { 
  14.             instance = new LanHanSingleton(); 
  15.         } 
  16.         return instance; 
  17.     } 
  18.  
  19.   

 

以上的例子,就是懶漢式的單例實現(xiàn)。實例在需要用到的時候,才去創(chuàng)建,就比較懶。如果有則返回,沒有則新建,需要加下 synchronized關(guān)鍵字,要不然可能存在線性安全問題。

6.2 單例模式的經(jīng)典寫法

其實單例模式還有有好幾種實現(xiàn)方式,如餓漢模式,雙重校驗鎖,靜態(tài)內(nèi)部類,枚舉等實現(xiàn)方式。

6.2.1 餓漢模式

 

  1. public class EHanSingleton { 
  2.  
  3.    private static EHanSingleton instance = new EHanSingleton(); 
  4.     
  5.    private EHanSingleton(){       
  6.    } 
  7.  
  8.    public static EHanSingleton getInstance() { 
  9.        return instance; 
  10.    } 
  11.     

 

餓漢模式,它比較饑餓、比較勤奮,實例在初始化的時候就已經(jīng)建好了,不管你后面有沒有用到,都先新建好實例再說。這個就沒有線程安全的問題,但是呢,浪費內(nèi)存空間呀。

6.2.2 雙重校驗鎖

 

  1. public class DoubleCheckSingleton { 
  2.  
  3.    private static DoubleCheckSingleton instance; 
  4.  
  5.    private DoubleCheckSingleton() { } 
  6.     
  7.    public static DoubleCheckSingleton getInstance(){ 
  8.        if (instance == null) { 
  9.            synchronized (DoubleCheckSingleton.class) { 
  10.                if (instance == null) { 
  11.                    instance = new DoubleCheckSingleton(); 
  12.                } 
  13.            } 
  14.        } 
  15.        return instance; 
  16.    } 

 

雙重校驗鎖實現(xiàn)的單例模式,綜合了懶漢式和餓漢式兩者的優(yōu)缺點。以上代碼例子中,在synchronized關(guān)鍵字內(nèi)外都加了一層 if條件判斷,這樣既保證了線程安全,又比直接上鎖提高了執(zhí)行效率,還節(jié)省了內(nèi)存空間。

6.2.3 靜態(tài)內(nèi)部類

 

  1. public class InnerClassSingleton { 
  2.  
  3.    private static class InnerClassSingletonHolder{ 
  4.        private static final InnerClassSingleton INSTANCE = new InnerClassSingleton(); 
  5.    } 
  6.  
  7.    private InnerClassSingleton(){} 
  8.     
  9.    public static final InnerClassSingleton getInstance(){ 
  10.        return InnerClassSingletonHolder.INSTANCE; 
  11.    } 

 

靜態(tài)內(nèi)部類的實現(xiàn)方式,效果有點類似雙重校驗鎖。但這種方式只適用于靜態(tài)域場景,雙重校驗鎖方式可在實例域需要延遲初始化時使用。

6.2.4 枚舉

 

  1. public enum SingletonEnum { 
  2.  
  3.     INSTANCE; 
  4.     public SingletonEnum getInstance(){ 
  5.         return INSTANCE; 
  6.     } 

枚舉實現(xiàn)的單例,代碼簡潔清晰。并且它還自動支持序列化機制,絕對防止多次實例化。

本文轉(zhuǎn)載自微信公眾號「撿田螺的小男孩」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系撿田螺的小男孩公眾號。

 

責(zé)任編輯:武曉燕 來源: 撿田螺的小男孩
相關(guān)推薦

2019-08-07 16:50:38

SQLjoingroup

2021-09-23 15:13:02

Spring依賴Java

2021-08-11 17:22:11

設(shè)計模式單例

2024-12-11 08:20:57

設(shè)計模式源碼

2021-04-18 21:07:32

門面模式設(shè)計

2021-08-28 11:47:52

json解析

2020-05-13 21:09:10

JavaScript前端技術(shù)

2024-04-28 11:22:18

2017-11-21 15:34:15

Linux 開發(fā)開源

2023-11-26 17:47:00

數(shù)據(jù)分析

2021-04-14 09:02:22

模式 設(shè)計建造者

2021-06-08 07:04:46

Dubbo設(shè)計模式

2022-09-21 09:01:27

Spring設(shè)計模式框架,

2022-12-13 08:23:25

CSS前端漸變

2024-02-19 08:38:34

建造者模式Android設(shè)計模式

2018-05-10 16:02:48

Android程序贈工具

2020-03-18 09:43:37

開發(fā)技能代碼

2024-11-26 14:29:48

2024-03-06 08:28:16

設(shè)計模式Java

2024-01-05 09:13:35

點贊
收藏

51CTO技術(shù)棧公眾號

一级黄色免费片| 国产sm调教视频| 天堂av在线网| 欧美—级在线免费片| 成人午夜一级二级三级| 精品97人妻无码中文永久在线| 91精品入口| 在线视频一区二区免费| 强伦女教师2:伦理在线观看| 色噜噜一区二区三区| 日本女优在线视频一区二区| 欧美成人三级视频网站| 91成人在线免费视频| 日本超碰一区二区| 在线观看av一区二区| 国产乱子伦精品无码专区| 国产在线日本| 成人高清视频在线观看| 国产日韩综合一区二区性色av| 国产精品suv一区二区69| 欧美手机视频| 亚洲精品国精品久久99热 | 欧洲一区二区在线| 亚洲国产日韩在线观看| 看片的网站亚洲| 欧美一级免费看| 欧美片一区二区| 99精品全国免费观看视频软件| 日韩精品久久久久| 中文字幕在线观看91| 日本国产一区| 91国产免费观看| 毛片在线视频播放| 污污的视频在线观看| 国产精品国产三级国产普通话99| 欧美大香线蕉线伊人久久| 午夜精品久久久久久久96蜜桃| 麻豆精品在线播放| 国产va免费精品高清在线| 99视频在线看| 亚洲性人人天天夜夜摸| 蜜月aⅴ免费一区二区三区| 一二三四在线观看视频| 国产一区二区三区探花| 亚洲精品中文字幕女同| 亚洲男人在线天堂| 久9re热视频这里只有精品| 欧美一区二区三区在| 久久国产这里只有精品| 精品亚洲a∨| 欧美日韩一区在线| 激情内射人妻1区2区3区| 裤袜国产欧美精品一区| 色综合久久综合网欧美综合网| 九色自拍视频在线观看| 91www在线| 婷婷久久综合九色综合伊人色| 国产精品久久久久久久久电影网| 羞羞视频在线观看不卡| 亚洲激情男女视频| 国产精品videossex国产高清| 国产成人无吗| 一二三四社区欧美黄| 国产免费一区二区视频| 538在线精品| 欧美日韩免费在线观看| 热久久精品国产| 成人黄色图片网站| 欧美精品 国产精品| 亚洲天堂av一区二区三区| 日本超碰一区二区| 亚洲成人亚洲激情| 国产精品1000部啪视频| 国内黄色精品| 久久精品小视频| 青青操国产视频| 一区二区国产精品| 国产精品成人免费电影| 亚洲天堂男人网| 国产一区二区在线视频| 国产成人女人毛片视频在线| 四虎影院在线播放| 欧美国产综合色视频| 国产精品无码乱伦| 国内老司机av在线| 91精品办公室少妇高潮对白| 三级一区二区三区| 成人性生交大片免费看中文视频| 日韩精品www| 国产精品一区二区亚洲| 国产一区久久| 国产成一区二区| 国产三级三级在线观看| 97aⅴ精品视频一二三区| 狠狠色噜噜狠狠色综合久| 国产精品一区在线看| 亚洲精品成人精品456| 18禁男女爽爽爽午夜网站免费| 免费成人黄色网| 亚洲国产免费av| 999精品久久久| 在线一区欧美| 成人淫片在线看| 深夜福利视频一区| 亚洲蜜臀av乱码久久精品蜜桃| 免费毛片小视频| 精品国产第一国产综合精品| 亚洲黄色有码视频| xxxx日本少妇| 日韩电影在线观看网站| 国产午夜精品一区| 九七久久人人| 色噜噜夜夜夜综合网| 国产a级片视频| 久久久久久久久久久久久久久久久久| 69视频在线免费观看| 国产绿帽刺激高潮对白| 国产日本欧美一区二区| 亚洲美免无码中文字幕在线 | 精品久久久久久久久久久久久久久久久| 中文字幕高清视频| 在线播放不卡| 91久久久一线二线三线品牌| 在线观看a视频| 福利一区福利二区微拍刺激| 亚洲黄色小说在线观看| 四虎成人av| 国产精品久久久久久中文字| 香蕉久久一区二区三区| 亚洲一区二区三区影院| 欧美性猛交xxxx乱大交91| 不卡中文一二三区| 国产999精品久久久| 午夜视频福利在线观看| 亚洲一区二区精品久久av| 国产美女视频免费看| 不卡日本视频| 国产欧美一区二区三区久久| 国产高清美女一级毛片久久| 欧美日韩在线观看视频| 中国极品少妇videossexhd| 欧美激情一区| 999视频在线免费观看| 国产激情在线| 欧美一区二区福利视频| 2025国产精品自拍| 国产在线视频一区二区三区| 最新欧美日韩亚洲| 亚洲国产伊人| www欧美日韩| 国产伦精品一区二区三区四区| 国产精品久久久久婷婷二区次| 黄色aaa级片| 91免费精品| 91在线直播亚洲| 中文字幕在线播放网址| 欧美一二三四区在线| 国产探花在线播放| 国产99精品在线观看| 中文精品无码中文字幕无码专区| 日韩中文字幕视频网| 久久久久国产精品免费| 秋霞视频一区二区| 欧美日韩亚洲91| 一级黄色片大全| 蜜臀av国产精品久久久久| 一区二区冒白浆视频| 三级欧美日韩| 2019亚洲日韩新视频| 免费福利在线视频| 欧美日韩国产片| 欧洲第一无人区观看| 99久久伊人网影院| 激情综合网俺也去| 五月天久久777| 国产精品视频500部| 成人私拍视频| 久久精品中文字幕电影| 免费观看黄色一级视频| 色视频欧美一区二区三区| 黄色国产在线播放| 国产成人午夜精品影院观看视频| 亚洲熟妇无码一区二区三区导航| 中日韩免视频上线全都免费| 国产综合久久久久久| 国产99re66在线视频| 亚洲欧美日韩综合| 国产欧美日韩成人| 五月婷婷久久丁香| 成年人看的免费视频| 成人午夜免费视频| 无需播放器的av| 激情综合视频| 日本黄色a视频| 羞羞色国产精品网站| 国产一区二区丝袜| 在线黄色的网站| 欧美美女18p| chinese偷拍一区二区三区| 日韩一级高清毛片| 亚洲中文字幕无码爆乳av| 一区二区三区欧美在线观看| 一区二区三区久久久久| 不卡的av在线| 小早川怜子一区二区三区| 亚洲综合不卡| 免费cad大片在线观看| 国产一区二区在线| 精品亚洲欧美日韩| 日韩黄色av| 国产精品视频免费在线| 麻豆国产在线| 欧美日韩国产第一页| 91精品国产91久久久久游泳池 | 乐播av一区二区三区| 福利一区二区在线观看| 天堂av在线8| 日本欧美一区二区在线观看| aa在线免费观看| 亚洲第一网站| 99久久99久久精品| 天天超碰亚洲| 亚洲三区视频| 国产精品密蕾丝视频下载| 国产偷久久久精品专区| 日韩在线视频一区二区三区 | 男女男精品视频站| 亚洲欧美春色| 1024av视频| 在线成人黄色| 农民人伦一区二区三区| 欧美三级视频| 免费看日本黄色| 欧美一区精品| japanese在线播放| 综合一区av| 一级性生活视频| 欧美一区国产在线| 日本黄网站色大片免费观看| 久久久久久久久国产一区| 中文字幕日韩一区二区三区不卡| 精品国产乱码久久久久久蜜坠欲下 | 欧日韩在线观看| 一区二区乱码| 热99精品里视频精品| 免费观看亚洲| 国产97在线|亚洲| 亚洲成人一区在线观看| 国产精品狠色婷| 久久青草免费| 91精品在线国产| 亚洲精品一区二区三区中文字幕| 亚洲一区二区久久久久久| 日本在线成人| 国产欧美精品一区二区三区| 老牛精品亚洲成av人片| 蜜桃91精品入口| 国产一区网站| 亚洲制服中文| 欧美极品一区二区三区| 少妇无码av无码专区在线观看 | 色天使在线观看| 韩国视频一区二区| 少妇欧美激情一区二区三区| 高清视频一区二区| 国产伦精品一区二区三区妓女 | 久久91导航| 国产精品一区电影| 韩国一区二区三区视频| 国产精品国产亚洲精品看不卡15| 精品福利一区| 色综合影院在线观看| 亚洲五月综合| www.中文字幕在线| 奇米精品一区二区三区四区| 国产高清999| 91网站在线播放| 日日操免费视频| 亚洲国产欧美在线人成| 男人天堂视频网| 91精品欧美福利在线观看| 内射无码专区久久亚洲| 亚洲图片在区色| 99福利在线| 日韩美女av在线免费观看| 99视频有精品高清视频| 精品高清视频| 水蜜桃精品av一区二区| 欧美日韩成人免费视频| 麻豆成人免费电影| 这里只有精品在线观看视频| 欧美经典一区二区三区| 久久综合久久鬼| 欧洲视频一区二区| 女人18毛片一区二区三区| 宅男66日本亚洲欧美视频| 男男gaygays亚洲| 国产精品流白浆视频| 国产精品一区二区中文字幕| 亚洲精品不卡| 亚洲综合99| 日本久久久久久久久久| 国产精品网曝门| 国偷自拍第113页| 日韩欧美国产精品一区| 国产精品久久一区二区三区不卡| 欧美日韩国产999| 久久爱.com| 免费国产一区| 精品99视频| 人妻体体内射精一区二区| 91色视频在线| 国产精品a成v人在线播放| 3751色影院一区二区三区| 精品影院一区| 97超碰国产精品女人人人爽| 欧美专区一区| 中国一区二区三区| 日韩电影在线看| 国产精品久久久久无码av色戒| 亚洲一区二区三区激情| 91亚洲国产成人精品一区| 亚洲午夜国产成人av电影男同| 丰满大乳少妇在线观看网站| 91影视免费在线观看| 成人精品视频| 久久午夜夜伦鲁鲁一区二区| 91在线一区二区三区| 国产精品第二十页| 日韩免费观看高清完整版 | 天天干天天摸天天操| 色综合天天综合网国产成人网| 婷婷成人av| 亚洲一区二区三区涩| 免费成人性网站| 亚洲av毛片基地| 色婷婷综合久久久久中文一区二区 | 亚洲午夜久久| 人妻精品无码一区二区三区| 久久中文字幕电影| 天天操夜夜操视频| 亚洲精品日韩欧美| 亚洲精品国产精品国产| 久久一区二区三区av| 国产精品最新自拍| 国产麻豆天美果冻无码视频| 午夜精品福利久久久| 无码国产伦一区二区三区视频| 国自产精品手机在线观看视频| 国产精品18hdxxxⅹ在线| 国产二区视频在线| av电影天堂一区二区在线观看| 日本在线小视频| 日韩成人中文字幕在线观看| 欧美男人天堂| 日韩黄色影视| 免费欧美在线视频| 亚洲区一区二区三| 欧美一区国产二区| 欧美黑人猛交| 久久草视频在线看| 国产精品视区| 高清国产在线观看| 欧美精品黑人性xxxx| av激情在线| 国产精品推荐精品| 久久九九国产| 任你操精品视频| 欧美成人精品福利| 自拍视频在线看| 亚洲国产精品久久久久婷婷老年| 麻豆精品视频在线观看视频| 成人观看免费视频| 亚洲精品国精品久久99热| 国产麻豆久久| 裸体大乳女做爰69| gogogo免费视频观看亚洲一| 黄色一级片免费在线观看| 中文字幕日韩欧美| 日韩视频一二区| 日韩 欧美 高清| 亚洲人成人一区二区在线观看| 国产成人自拍一区| 国产精品99久久久久久白浆小说| 日韩欧美高清| 国产精品成人99一区无码| 欧美在线观看禁18| 国精产品一区一区三区mba下载| 欧美xxxx黑人又粗又长密月| 精油按摩中文字幕久久| 国产在线视频99| 中文字幕亚洲情99在线| 国产精东传媒成人av电影| 最新天堂中文在线| 亚洲一区二区精品视频| 日本美女在线中文版| 久久精品成人一区二区三区蜜臀 | 成人国产精品一区| 国产日韩一区二区三区在线播放 | 欧美色窝79yyyycom|