日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
命令模式之中介者模式

最近在跟大家分享設(shè)計(jì)模式系列的文章有學(xué)妹問我,命令模式、策略模式、工廠模式 它們分別有啥區(qū)別?看代碼的實(shí)現(xiàn)上感覺沒啥區(qū)別呀?

為石龍等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計(jì)制作服務(wù),及石龍網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為成都網(wǎng)站建設(shè)、做網(wǎng)站、石龍網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!

我說:文章可能有點(diǎn)長,你忍一下

之前已經(jīng)跟大家分享了策略模式以及工廠模式感興趣的同學(xué)可以再去復(fù)習(xí)一下,今天我們就先重點(diǎn)分析一下命令模式然后再來看看它們的區(qū)別是啥?

命令模式

定義

  • 提供一個(gè)統(tǒng)一的方法來封裝命令,通過參數(shù)條件來判斷選擇執(zhí)行什么命令動作。
  • 允許將每一個(gè)命令存儲在一個(gè)隊(duì)列中。

整體結(jié)構(gòu)圖如下:

結(jié)構(gòu)圖中重要角色解釋:

  • Command(命令類):定義命令的抽象封裝類。
  • ConcreteCommand(具體命令類):對Command類進(jìn)行實(shí)現(xiàn),說白了就是具體的命令的實(shí)際實(shí)現(xiàn)類。
  • Receiver(接收者):執(zhí)行命令關(guān)聯(lián)的操作類。
  • Invoker(調(diào)用者):觸發(fā)命令類,即外部操作事件觸發(fā)執(zhí)行。
  • Client(客戶端):實(shí)例化具體命令對象,及接收者的實(shí)際類。

整個(gè)結(jié)構(gòu)其實(shí)看上去還是比較難理解的,但是既然開始在學(xué)設(shè)計(jì)模式了,那肯定每種設(shè)計(jì)模式都要有了解,來提升自己的知識面

為了加深理解,我還是舉一個(gè)好理解的例子:

大家對中國古代君主制度肯定很熟悉。皇帝可以針對手底下服侍的公公讓她們可以收取或者發(fā)放奏折。那其實(shí)這里面我個(gè)人感覺就可以體現(xiàn)命令模式。

公公 相當(dāng)于命令模式的接受者(Receiver),執(zhí)行皇帝的命令,收取早朝奏折(ConcreteCommand) 還是頒布圣旨(ConcreteCommand)

皇帝 相當(dāng)于命令模式的調(diào)用者(Invoker)

老規(guī)矩,例子說完,看看代碼吧!

 
 
 
 
  1. // 定義 命令類 
  2. public interface Command { 
  3.     // 執(zhí)行的方法 
  4.     void execute(); 
  5.  
  6. // 定義接收者-公公的角色 
  7. public class Receiver { 
  8.  
  9.     public void Charge(){ 
  10.         System.out.println("收取奏折"); 
  11.     } 
  12.  
  13.     public void Issue(){ 
  14.         System.out.println("頒布圣旨"); 
  15.     } 
  16.  
  17.  
  18. //具體命令類one,收取奏折命令 
  19. public class ConcreteCommandOne implements Command { 
  20.  
  21.     // 接受者,這里可以理解為公公 
  22.     private Receiver receiver; 
  23.  
  24.     public ConcreteCommandOne(Receiver receiver) { 
  25.         this.receiver = receiver; 
  26.     } 
  27.  
  28.     @Override 
  29.     public void execute() { 
  30.         // 收取奏折 
  31.         receiver.Charge(); 
  32.     } 
  33.  
  34. // 具體命令類two,頒布圣旨 
  35. public class ConcreteCommandTwo implements Command { 
  36.  
  37.     // 接受者,這里可以理解為公公 
  38.     private Receiver receiver; 
  39.  
  40.     public ConcreteCommandTwo(Receiver receiver) { 
  41.         this.receiver = receiver; 
  42.     } 
  43.  
  44.     @Override 
  45.     public void execute() { 
  46.         // 頒布圣旨 
  47.         receiver.Issue(); 
  48.     } 
  49.  
  50. // 調(diào)用者,皇帝 
  51. public class Invoker { 
  52.    
  53.     private Command command; 
  54.  
  55.     public Invoker(Command command) { 
  56.         this.command = command; 
  57.     } 
  58.     // 本次需要執(zhí)行的命令 
  59.     public void action() { 
  60.         command.execute(); 
  61.     } 
  62.  
  63.  // 測試demo 
  64.     public static void main(String[] args) { 
  65.         // 實(shí)例化一個(gè)公公 接收者 
  66.         Receiver receiver =new Receiver(); 
  67.         // 公公 當(dāng)前能有接收到的幾種命令 
  68.         Command commandOne = new ConcreteCommandOne(receiver); 
  69.         Command commandTwo = new ConcreteCommandTwo(receiver); 
  70.  
  71.         // 皇帝 發(fā)號命令 觸發(fā)執(zhí)行方法 
  72.         Invoker invoker =new Invoker(commandOne); 
  73.         invoker.action(); 
  74.         // result: 收取奏折 
  75.  
  76.         Invoker invokerTwo =new Invoker(commandTwo); 
  77.         invokerTwo.action(); 
  78.         // result:頒布圣旨 
  79.     } 

以上就是簡單的代碼實(shí)現(xiàn)了,通過Invoker(皇帝)的選擇可以讓Receiver(公公)確定去執(zhí)行什么命令。這其實(shí)就是命令模式的一種簡單體現(xiàn)。

細(xì)心的同學(xué)不知道有沒有發(fā)現(xiàn)一個(gè)問題,在定義里面

  • 允許將每一個(gè)命令存儲在一個(gè)隊(duì)列中。

我們這里是沒有體現(xiàn)隊(duì)列的,其實(shí)這個(gè)實(shí)現(xiàn)也很簡單。在main方法中添加一個(gè)隊(duì)列就可以了。

 
 
 
 
  1. public static void main(String[] args) { 
  2.     // 實(shí)例化一個(gè)公公 接收者 
  3.     Receiver receiver = new Receiver(); 
  4.     // 公公 當(dāng)前能有接收到的幾種命令 
  5.     Command commandOne = new ConcreteCommandOne(receiver); 
  6.     Command commandTwo = new ConcreteCommandTwo(receiver); 
  7. // 存儲命令 
  8.     Queue queue = new LinkedList<>(); 
  9.     queue.add(commandOne); 
  10.     queue.add(commandTwo); 
  11. // 批量執(zhí)行 
  12.     for (Command command : queue) { 
  13.         Invoker invoker = new Invoker(command); 
  14.         invoker.action(); 
  15.     } 

這里我想給大家做一個(gè)擴(kuò)展點(diǎn),這也是我之前看到過一種校驗(yàn)寫法。

大家在真實(shí)的工作中肯定會遇到很多一些接口的校驗(yàn),怎么去寫這個(gè)校驗(yàn)邏輯,怎么做到代碼的復(fù)用、抽象等這其實(shí)是一個(gè)比較難的問題!

還是大致的來看下結(jié)構(gòu)圖吧!!!

demo代碼,我也給大家寫出來,需要注意的是我們需要實(shí)現(xiàn) ApplicationContextAware 里面的afterPropertiesSet 方法。

 
 
 
 
  1. // 定義抽象校驗(yàn)方法 
  2. public abstract class ValidatePlugin { 
  3.     public abstract void validate(); 
  4. // 抽象規(guī)則執(zhí)行器 
  5. public abstract class ValidatePluginExecute { 
  6.     protected abstract List getValidatePlugins(); 
  7.     public void execute() { 
  8.         final List validatePlugins = getValidatePlugins(); 
  9.         if (CollectionUtils.isEmpty(validatePlugins)) { 
  10.             return; 
  11.         } 
  12.         for (ValidatePlugin validatePlugin : validatePlugins) { 
  13.           // 執(zhí)行校驗(yàn)邏輯,這里大家可以根據(jù)自己的實(shí)際業(yè)務(wù)場景改造 
  14.             validatePlugin.validate(); 
  15.         } 
  16.     } 
  17.  
  18. // 具體測試規(guī)則 
  19. @Component("validatePluginOne") 
  20. public class ValidatePluginOne extends  ValidatePlugin { 
  21.     @Override 
  22.     public void validate() { 
  23.         System.out.println("validatePluginOne 規(guī)則校驗(yàn)"); 
  24.     } 
  25.  
  26. // 具體執(zhí)行器,把需要執(zhí)行的規(guī)則添加到 validatePlugins 中 
  27. @Component("testValidatePlugin") 
  28. public class TestValidatePlugin extends ValidatePluginExecute implements ApplicationContextAware, InitializingBean { 
  29.  
  30.     protected ApplicationContext applicationContext; 
  31.  
  32.     private List validatePlugins; 
  33.  
  34.     @Override 
  35.     public void afterPropertiesSet() { 
  36.       // 添加規(guī)則 
  37.         validatePlugins = Lists.newArrayList(); 
  38.         validatePlugins.add((ValidatePlugin) this.applicationContext.getBean("validatePluginOne")); 
  39.  
  40.     } 
  41.  
  42.     @Override 
  43.     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
  44.         this.applicationContext = applicationContext; 
  45.     } 
  46.  
  47.     @Override 
  48.     protected List getValidatePlugins() { 
  49.         return this.validatePlugins; 
  50.     } 
  51.  
  52. // 測試demo 
  53.   public static void main(String[] args) { 
  54.         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); 
  55.         TestValidatePlugin testValidatePlugin = (TestValidatePlugin) applicationContext.getBean("testValidatePlugin"); 
  56.         testValidatePlugin.execute(); 
  57.     } 

這個(gè)只是一個(gè)簡單的測試demo,為了讓大家有一個(gè)思考,設(shè)計(jì)模式不一定是照搬代碼。更多是開拓自己的視野,提升自己解決問題的能力。

針對不同的一些接口,我們只需要在TestValidatePlugin 中添加具體校驗(yàn)規(guī)則就可以了,整體的擴(kuò)展性就變高了,看上去也比較高大上。

所以上面提到的命令模式、策略模式、工廠模式區(qū)別是什么呢?

  • 命令模式:屬于行為型設(shè)計(jì)模式,在命令模式中,不同的命令執(zhí)行過程中會產(chǎn)生不同的目的結(jié)果,而且不同的命令是不能替換的。
  • 策略模式 :屬于行為型設(shè)計(jì)模式,在策略模式中,重點(diǎn)在于針對每一種策略執(zhí)行,解決根據(jù)運(yùn)行時(shí)狀態(tài)從一組策略中選擇不同策略的問題
  • 工廠模式:屬于創(chuàng)建型設(shè)計(jì)模式,在工廠模式中,重點(diǎn)在于封裝對象的創(chuàng)建過程,這里的對象沒有任何業(yè)務(wù)場景的限定,可以是策略,但也可以是其他東西

所以針對設(shè)計(jì)模式,其實(shí)我理解的還是只說明了一個(gè)問題,不同的設(shè)計(jì)模式都是為了針對處理不同的場景,不同業(yè)務(wù)場景有不同的寫法。

中介者模式

中介者模式,看這個(gè)名字也能理解出來,定一個(gè)中間結(jié)構(gòu)來方便管理下游組織。

那么什么是中介模式呢?

  • 在GoF 中的《設(shè)計(jì)模式》中解釋為:中介模式定義了一個(gè)單獨(dú)的(中介)對象,來封裝一組對象之間的交互。將這組對象之間的交互委派給與中介對象交互,來避免對象之間的直接交互。

再來看看這個(gè)結(jié)構(gòu)圖吧:

  • Mediator(抽象中介者):用來定義參與者與中介者之間的交互方式
  • ConcreteMediator(具體中介者):實(shí)現(xiàn)中介者定義的操作,即就是實(shí)現(xiàn)交互方式。
  • Colleague(抽象同事角色):抽象類或者接口,主要用來定義參與者如何進(jìn)行交互。
  • ConcreteColleague(具有同事角色):很簡單,就是具體的實(shí)現(xiàn)Colleague中的方法。

以上結(jié)構(gòu)定義來自設(shè)計(jì)模式之美

看這個(gè)結(jié)構(gòu)圖理解出來,其實(shí)是跟之前為大家寫的一篇觀察者模式有點(diǎn)相同的,感興趣的同學(xué)可以再去復(fù)習(xí)一下。

老規(guī)矩,還是具體舉例代碼實(shí)現(xiàn)一下

高鐵系統(tǒng)大家應(yīng)該清楚有一個(gè)調(diào)度中心,用來控制每一輛高鐵的進(jìn)站順序,如果沒有這個(gè)調(diào)度中心,當(dāng)同時(shí)有三量高鐵都即將進(jìn)站時(shí),那他們就需要兩兩相護(hù)溝通。

假設(shè)有其中的一輛動車沒有溝通到,那就將發(fā)生不可估量的錯誤,所以就需要通過這個(gè)調(diào)度中心來處理這個(gè)通信邏輯,同時(shí)來管理當(dāng)前有多少車輛等待進(jìn)站等。

 
 
 
 
  1. // 抽象參與者, 也可以使用abstract 寫法 
  2. public interface Colleague { 
  3.    // 溝通消息 
  4.     void message(); 
  5. // 抽象中介者 
  6. public interface Mediator { 
  7.     // 定義處理邏輯 
  8.     void doEvent(Colleague colleague); 
  9.  
  10. // 具體參與者 
  11. @Component 
  12. public class MotorCarOneColleague implements Colleague { 
  13.  
  14.     @Override 
  15.     public void message() { 
  16.         // 模擬處理業(yè)務(wù)邏輯 
  17.         System.out.println("高鐵一號收到消息?。。?); 
  18.     } 
  19. @Component 
  20. public class MotorCarTwoColleague implements Colleague { 
  21.     @Override 
  22.     public void message() { 
  23.         System.out.println("高鐵二號收到消息?。。?); 
  24.     } 
  25. @Component 
  26. public class MotorCarThreeColleague implements Colleague { 
  27.     @Override 
  28.     public void message() { 
  29.         System.out.println("高鐵三號收到消息?。?!"); 
  30.     } 
  31.  
  32. // 具體中介者 
  33. @Component 
  34. public class DispatchCenter implements Mediator { 
  35.   // 管理有哪些參與者 
  36.     @Autowired 
  37.     private List colleagues; 
  38.    
  39.     @Override 
  40.     public void doEvent(Colleague colleague) { 
  41.         for(Colleague colleague1 :colleagues){ 
  42.             if(colleague1==colleague){ 
  43.                 // 如果是本身高鐵信息,可以處理其他的業(yè)務(wù)邏輯 
  44.                 // doSomeThing(); 
  45.                 continue; 
  46.             } 
  47.           // 通知其他參與 
  48.             colleague1.message(); 
  49.         } 
  50.     } 
  51.  
  52. // 測試demo 
  53. public static void main(String[] args) { 
  54.      // 初始化spring容器 
  55.         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); 
  56.      // 獲取中介者,調(diào)度中心 
  57.         DispatchCenter dispatchCenter = (DispatchCenter) applicationContext.getBean("dispatchCenter"); 
  58.  
  59.  
  60.         // 一號高鐵 發(fā)送消息出去 
  61.         MotorCarOneColleague motorCarOneColleague =  (MotorCarOneColleague) applicationContext.getBean("motorCarOneColleague"); 
  62.      // 通過調(diào)度中心溝通信息 
  63.         dispatchCenter.doEvent(motorCarOneColleague); 
  64.         // result:高鐵三號收到消息?。?! 
  65.         //         高鐵二號收到消息?。?! 
  66.  
  67.  
  68.         // 二號高鐵 發(fā)送消息出去 
  69.         MotorCarTwoColleague  motorCarTwoColleague = (MotorCarTwoColleague)applicationContext.getBean("motorCarTwoColleague"); 
  70.         dispatchCenter.doEvent(motorCarTwoColleague); 
  71.         // result:高鐵一號收到消息!??! 
  72.         //         高鐵三號收到消息!??! 
  73.  
  74.     } 

中介者模式demo代碼就算完成了,通過這個(gè)demo大家應(yīng)該能發(fā)現(xiàn),中介者還是很好理解的。

但是中介者的應(yīng)用場景還是比較少見的,針對一些類依賴嚴(yán)重,形成的類似網(wǎng)狀結(jié)構(gòu),改成一個(gè)類似與蒲公英一樣結(jié)構(gòu),由中間向外擴(kuò)散,來達(dá)到解耦合的效果。

更多在一個(gè)UI界面控件里面比較常見,當(dāng)然在Java里面java.util.Timer 也可以理解為中介者模式,因?yàn)樗芸刂苾?nèi)部線程如何去運(yùn)行比如多久運(yùn)行一次等。

上面提到中介者和觀察者模式很像,通過demo代碼大家也能發(fā)現(xiàn)這一點(diǎn)

觀察者模式中觀察者和被觀察者我們基本時(shí)固定的,而中介者模式中,觀察者和被觀察者時(shí)不固定的,而且中介者可能會最后變成一個(gè)龐大的原始類。

總結(jié)

命令模式:雖然不怎么常見,但是我們還是要區(qū)分它與工廠模式以及策略模式的區(qū)別是啥,應(yīng)用場景是啥,能給我們帶來什么思考。

比如我最后的那個(gè)例子,命令模式可以實(shí)現(xiàn)命令的存儲,本質(zhì)是將命令維護(hù)在一個(gè)隊(duì)列中,那么在我們的業(yè)務(wù)代碼中 我們?yōu)槭裁床荒芤餐ㄟ^一個(gè)數(shù)組來維護(hù)一些接口校驗(yàn)依賴,里面存放需要校驗(yàn)的bean實(shí)例。來提高代碼的復(fù)用性以及擴(kuò)展性。

中介模式:整體來說這個(gè)更加不怎么應(yīng)用,雖然能起到對象的解耦合,但是也有副作用,而且在我們的真實(shí)業(yè)務(wù)場景中也很少會遇到這樣的場景,了解一下實(shí)現(xiàn)原理即可,至于與觀察者的區(qū)別,上面也有講到,更多我們可能是已經(jīng)在使用一些中間件消息隊(duì)列去處理了。

我是敖丙,你知道的越多,你不知道的越多,我們下期見!


網(wǎng)頁名稱:命令模式之中介者模式
文章鏈接:http://www.dlmjj.cn/article/djcgsio.html