外觀模式與中介者模式的異同點(設計模式系列中介者模式)
2023-04-13 15:10:38 5
作者公眾號:一角錢技術(org_yijiaoqian)
前言23種設計模式速記單例(singleton)模式工廠方法(factory method)模式抽象工廠(abstract factory)模式建造者/構建器(builder)模式原型(prototype)模式享元(flyweight)模式外觀(facade)模式適配器(adapter)模式裝飾(decorator)模式觀察者(observer)模式策略(strategy)模式橋接(bridge)模式模版方法(template method)模式責任鏈(chain of responsibility)模式組合(composite)模式代理(proxy)模式備忘錄(memento)模式命令(command)模式狀態(state)模式持續更新中......23種設計模式快速記憶的請看上面第一篇,本篇和大家一起來學習中介者模式相關內容。
定義一個中介對象來封裝一系列對象之間的交互,使原有對象之間的耦合鬆散,且可以獨立地改變它們之間的交互。中介者模式又叫調停模式,它是迪米特法則的典型應用。
迪米特法則(Law of Demeter,LoD)又叫作最少知識原則(Least Knowledge Principle,LKP),產生於 1987 年美國東北大學(Northeastern University)的一個名為迪米特(Demeter)的研究項目,由伊恩·荷蘭(Ian Holland)提出,被 UML 創始者之一的布奇(Booch)普及,後來又因為在經典著作《程式設計師修煉之道》(The Pragmatic Programmer)提及而廣為人知。
迪米特法則的定義是:只與你的直接朋友交談,不跟「陌生人」說話(Talk only to your immediate friends and not to strangers)。其含義是:如果兩個軟體實體無須直接通信,那麼就不應當發生直接的相互調用,可以通過第三方轉發該調用。其目的是降低類之間的耦合度,提高模塊的相對獨立性。
迪米特法則中的「朋友」是指:當前對象本身、當前對象的成員對象、當前對象所創建的對象、當前對象的方法參數等,這些對象同當前對象存在關聯、聚合或組合關係,可以直接訪問這些對象的方法。
模板實現如下:
packagecom.niuh.designpattern.mediator.v1;importjava.util.ArrayList;importjava.util.List;/****中介者模式**/publicclassMediatorPattern{publicstaticvoidmain(String[]args){Mediatormd=newConcreteMediator;Colleaguec1,c2;c1=newConcreteColleague1;c2=newConcreteColleague2;md.register(c1);md.register(c2);c1.send;System.out.println("==============");c2.send;}}//抽象中介者abstractclassMediator{publicabstractvoidregister(Colleaguecolleague);publicabstractvoidrelay(Colleaguecl);//轉發}//具體中介者classConcreteMediatorextendsMediator{privateListcolleagues=newArrayList;publicvoidregister(Colleaguecolleague){if(!colleagues.contains(colleague)){colleagues.add(colleague);colleague.setMedium(this);}}publicvoidrelay(Colleaguecl){for(Colleagueob:colleagues){if(!ob.equals(cl)){((Colleague)ob).receive;}}}}//抽象同事類abstractclassColleague{protectedMediatormediator;publicvoidsetMedium(Mediatormediator){this.mediator=mediator;}publicabstractvoidreceive;publicabstractvoidsend;}//具體同事類classConcreteColleague1extendsColleague{publicvoidreceive{System.out.println("具體同事類1收到請求。");}publicvoidsend{System.out.println("具體同事類1發出請求。");mediator.relay(this);//請中介者轉發}}//具體同事類classConcreteColleague2extendsColleague{publicvoidreceive{System.out.println("具體同事類2收到請求。");}publicvoidsend{System.out.println("具體同事類2發出請求。");mediator.relay(this);//請中介者轉發}}
結果實現如下:
具體同事類1發出請求。具體同事類2收到請求。==============具體同事類2發出請求。具體同事類1收到請求。
解決的問題對象與對象之間存在大量的關聯關係,這樣勢必會導致系統的結構變得很複雜,同時若一個對象發生改變,我們也需要跟蹤與之相關聯的對象,同時做出相應的處理。
模式組成中介者模式實現的關鍵是找出「中介者」。
用中介者模式編寫一個「北京房地產交流平臺」程序。
分析:北京房地產交流平臺是「房地產中介公司」提供給「賣方客戶」與「買方客戶」進行信息交流的平臺,比較適合用中介者模式來實現。
步驟1:定義一個中介公司(Medium)接口,它是抽象中介者,它包含了客戶註冊方法 register(Customer member) 和信息轉發方法 relay(String from,String ad);
interfaceMedium{//客戶註冊voidregister(Customermember);//轉發voidrelay(Stringfrom,Stringad);}
步驟2:定義一個北京房地產中介(EstateMedium)公司,它是具體中介者類,它包含了保存客戶信息的 List 對象,並實現了中介公司中的抽象方法。
//具體中介者:房地產中介classEstateMediumimplementsMedium{privateListmembers=newArrayList;publicvoidregister(Customermember){if(!members.contains(member)){members.add(member);member.setMedium(this);}}publicvoidrelay(Stringfrom,Stringad){for(Customerob:members){Stringname=ob.getName;if(!name.equals(from)){((Customer)ob).receive(from,ad);}}}}
步驟3:定義一個客戶(Qistomer)類,它是抽象同事類,其中包含了中介者的對象,和發送信息的 send(String ad) 方法與接收信息的 receive(String from,Stringad) 方法的接口,由於本程序是窗體程序,所以本類繼承 JPmme 類,並實現動作事件的處理方法 actionPerformed(ActionEvent e)。
//抽象同事類:客戶abstractclassCustomerextendsJFrameimplementsActionListener{privatestaticfinallongserialVersionUID=-7219939540794786080L;protectedMediummedium;protectedStringname;JTextFieldSentText;JTextAreaReceiveArea;publicCustomer(Stringname){super(name);this.name=name;}voidClientWindow(intx,inty){Containercp;JScrollPanesp;JPanelp1,p2;cp=this.getContentPane;SentText=newJTextField(18);ReceiveArea=newJTextArea(10,18);ReceiveArea.setEditable(false);p1=newJPanel;p1.setBorder(BorderFactory.createTitledBorder("接收內容:"));p1.add(ReceiveArea);sp=newJScrollPane(p1);cp.add(sp,BorderLayout.NORTH);p2=newJPanel;p2.setBorder(BorderFactory.createTitledBorder("發送內容:"));p2.add(SentText);cp.add(p2,BorderLayout.SOUTH);SentText.addActionListener(this);this.setLocation(x,y);this.setSize(250,330);this.setResizable(false);//窗口大小不可調整this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setVisible(true);}publicvoidactionPerformed(ActionEvente){StringtempInfo=SentText.getText.trim;SentText.setText("");this.send(tempInfo);}publicStringgetName{returnname;}publicvoidsetMedium(Mediummedium){this.medium=medium;}publicabstractvoidsend(Stringad);publicabstractvoidreceive(Stringfrom,Stringad);}
步驟4:定義賣方(Seller)類和買方(Buyer)類,它們是具體同事類,是客戶(Customer)類的子類,它們實現了父類中的抽象方法,通過中介者類進行信息交流。
//具體同事類:賣方classSellerextendsCustomer{privatestaticfinallongserialVersionUID=-1443076716629516027L;publicSeller(Stringname){super(name);ClientWindow(50,100);}publicvoidsend(Stringad){ReceiveArea.append("我(賣方)說:" ad "\n");//使滾動條滾動到最底端ReceiveArea.setCaretPosition(ReceiveArea.getText.length);medium.relay(name,ad);}publicvoidreceive(Stringfrom,Stringad){ReceiveArea.append(from "說:" ad "\n");//使滾動條滾動到最底端ReceiveArea.setCaretPosition(ReceiveArea.getText.length);}}//具體同事類:買方classBuyerextendsCustomer{privatestaticfinallongserialVersionUID=-474879276076308825L;publicBuyer(Stringname){super(name);ClientWindow(350,100);}publicvoidsend(Stringad){ReceiveArea.append("我(買方)說:" ad "\n");//使滾動條滾動到最底端ReceiveArea.setCaretPosition(ReceiveArea.getText.length);medium.relay(name,ad);}publicvoidreceive(Stringfrom,Stringad){ReceiveArea.append(from "說:" ad "\n");//使滾動條滾動到最底端ReceiveArea.setCaretPosition(ReceiveArea.getText.length);}}
輸出結果當同事類太多時,中介者的職責將很大,它會變得複雜而龐大,以至於系統難以維護。
應用場景當對象之間存在複雜的網狀結構關係而導致依賴關係混亂且難以復用時。當想創建一個運行於多個類之間的對象,又不想生成新的子類時。模式的擴展在實際開發中,通常採用以下兩種方法來簡化中介者模式,使開發變得更簡單。
不定義中介者接口,把具體中介者對象實現成為單例。同事對象不持有中介者,而是在需要的時候直接獲取中介者對象並調用。程序代碼如下:
packagecom.niuh.designpattern.mediator.v3;importjava.util.ArrayList;importjava.util.List;/****簡化中介者模式**/publicclassSimpleMediatorPattern{publicstaticvoidmain(String[]args){SimpleColleaguec1,c2;c1=newSimpleConcreteColleague1;c2=newSimpleConcreteColleague2;c1.send;System.out.println("==============");c2.send;}}//簡單單例中介者classSimpleMediator{privatestaticSimpleMediatorsmd=newSimpleMediator;privateListcolleagues=newArrayList;privateSimpleMediator{}publicstaticSimpleMediatorgetMedium{return(smd);}publicvoidregister(SimpleColleaguecolleague){if(!colleagues.contains(colleague)){colleagues.add(colleague);}}publicvoidrelay(SimpleColleaguescl){for(SimpleColleagueob:colleagues){if(!ob.equals(scl)){((SimpleColleague)ob).receive;}}}}//抽象同事類interfaceSimpleColleague{voidreceive;voidsend;}//具體同事類classSimpleConcreteColleague1implementsSimpleColleague{SimpleConcreteColleague1{SimpleMediatorsmd=SimpleMediator.getMedium;smd.register(this);}publicvoidreceive{System.out.println("具體同事類1:收到請求。");}publicvoidsend{SimpleMediatorsmd=SimpleMediator.getMedium;System.out.println("具體同事類1:發出請求...");smd.relay(this);//請中介者轉發}}//具體同事類classSimpleConcreteColleague2implementsSimpleColleague{SimpleConcreteColleague2{SimpleMediatorsmd=SimpleMediator.getMedium;smd.register(this);}publicvoidreceive{System.out.println("具體同事類2:收到請求。");}publicvoidsend{SimpleMediatorsmd=SimpleMediator.getMedium;System.out.println("具體同事類2:發出請求...");smd.relay(this);//請中介者轉發}}
輸出結果如下:
具體同事類1:發出請求...具體同事類2:收到請求。==============具體同事類2:發出請求...具體同事類1:收到請求。
源碼中的應用java.util.Timerjava.util.concurrent.Executer#executejava.util.concurrent.ExecuterService#submitjava.lang.reflect.Method#invoke
PS:以上代碼提交在 Github :
https://github.com/Niuh-Study/niuh-designpatterns.git
文章持續更新,可以公眾號搜一搜「 一角錢技術 」第一時間閱讀, 本文 GitHub org_hejianhui/JavaStudy 已經收錄,歡迎 Star。
,