外观模式与中介者模式的异同点(设计模式系列中介者模式)

外观模式与中介者模式的异同点(设计模式系列中介者模式)(1)

作者公众号:一角钱技术(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种设计模式快速记忆的请看上面第一篇,本篇和大家一起来学习中介者模式相关内容。

外观模式与中介者模式的异同点(设计模式系列中介者模式)(2)

模式定义

定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。中介者模式又叫调停模式,它是迪米特法则的典型应用。

迪米特法则(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)。其含义是:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。

迪米特法则中的“朋友”是指:当前对象本身、当前对象的成员对象、当前对象所创建的对象、当前对象的方法参数等,这些对象同当前对象存在关联、聚合或组合关系,可以直接访问这些对象的方法。

外观模式与中介者模式的异同点(设计模式系列中介者模式)(3)

模板实现如下

packagecom.niuh.designpattern.mediator.v1; importjava.util.ArrayList; importjava.util.List; /** *<p> *中介者模式 *</p> */ 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{ privateList<Colleague>colleagues=newArrayList<Colleague>(); 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收到请求。

解决的问题

对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。

模式组成

中介者模式实现的关键是找出“中介者”。

外观模式与中介者模式的异同点(设计模式系列中介者模式)(4)

实例说明实例概况

用中介者模式编写一个“北京房地产交流平台”程序。

分析:北京房地产交流平台是“房地产中介公司”提供给“卖方客户”与“买方客户”进行信息交流的平台,比较适合用中介者模式来实现。

外观模式与中介者模式的异同点(设计模式系列中介者模式)(5)

使用步骤

步骤1:定义一个中介公司(Medium)接口,它是抽象中介者,它包含了客户注册方法 register(Customer member) 和信息转发方法 relay(String from,String ad);

interfaceMedium{ //客户注册 voidregister(Customermember); //转发 voidrelay(Stringfrom,Stringad); }

步骤2:定义一个北京房地产中介(EstateMedium)公司,它是具体中介者类,它包含了保存客户信息的 List 对象,并实现了中介公司中的抽象方法。

//具体中介者:房地产中介 classEstateMediumimplementsMedium{ privateList<Customer>members=newArrayList<Customer>(); 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()); } }

输出结果

外观模式与中介者模式的异同点(设计模式系列中介者模式)(6)

优点
  1. 降低了对象之间的耦合性,使得对象易于独立地被复用。
  2. 将对象间的一对多关联转变为一对一的关联,提高系统的灵活性,使得系统易于维护和扩展。
缺点

当同事类太多时,中介者的职责将很大,它会变得复杂而庞大,以至于系统难以维护。

应用场景
  • 当对象之间存在复杂的网状结构关系而导致依赖关系混乱且难以复用时。
  • 当想创建一个运行于多个类之间的对象,又不想生成新的子类时。
模式的扩展

在实际开发中,通常采用以下两种方法来简化中介者模式,使开发变得更简单。

  1. 不定义中介者接口,把具体中介者对象实现成为单例。
  2. 同事对象不持有中介者,而是在需要的时候直接获取中介者对象并调用。

外观模式与中介者模式的异同点(设计模式系列中介者模式)(7)

程序代码如下

packagecom.niuh.designpattern.mediator.v3; importjava.util.ArrayList; importjava.util.List; /** *<p> *简化中介者模式 *</p> */ publicclassSimpleMediatorPattern{ publicstaticvoidmain(String[]args){ SimpleColleaguec1,c2; c1=newSimpleConcreteColleague1(); c2=newSimpleConcreteColleague2(); c1.send(); System.out.println("=============="); c2.send(); } } //简单单例中介者 classSimpleMediator{ privatestaticSimpleMediatorsmd=newSimpleMediator(); privateList<SimpleColleague>colleagues=newArrayList<SimpleColleague>(); 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.Timer java.util.concurrent.Executer#execute() java.util.concurrent.ExecuterService#submit() java.lang.reflect.Method#invoke()

PS:以上代码提交在 Github

https://github.com/Niuh-Study/niuh-designpatterns.git

文章持续更新,可以公众号搜一搜「 一角钱技术 」第一时间阅读, 本文 GitHub org_hejianhui/JavaStudy 已经收录,欢迎 Star。

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页