为了解决我的一些问题,我一直在阅读《四人帮》,并遇到了Mediator模式。
我之前在项目中使用Observer来制作一些GUI应用程序。我有点困惑,因为我发现两者之间没有太大区别。我浏览找到了区别,但没有找到适合我的查询的答案。
有人可以帮我用一个很好的例子来区分两者吗?
为了解决我的一些问题,我一直在阅读《四人帮》,并遇到了Mediator模式。
我之前在项目中使用Observer来制作一些GUI应用程序。我有点困惑,因为我发现两者之间没有太大区别。我浏览找到了区别,但没有找到适合我的查询的答案。
有人可以帮我用一个很好的例子来区分两者吗?
ChangeManager
的Observer
模式,在实现部分#8下解决了该问题Mediator
。看到; paginas.fe.up.pt/~aaguiar/as/gof/hires/pat5g.htm#samplecode
Answers:
观察者模式:定义对象之间的一对多依赖关系,以便当一个对象改变状态时,其所有依赖关系都将得到通知并自动更新。
中介者模式:定义一个对象,该对象封装了一组对象之间的交互方式。介体通过防止对象之间显式地相互引用来促进松散耦合,并且它使您可以独立地更改其交互。
资料来源:工厂
例:
观察者模式:A类,可以向其注册零个或多个O类型的观察者。当A中的某些内容发生更改时,它会通知所有观察者。
中介者模式:您有一些类X的实例(甚至可能有几种不同的类型:X,Y和Z),并且它们希望彼此通信(但您不希望每个实例对每个实例都有明确的引用)其他),因此您创建了一个调解器类M。X的每个实例都有对M共享实例的引用,通过它可以与X的其他实例(或X,Y和Z)进行通信。
在创造了术语“观察者和中介者”,“ 设计模式”,“可重用的面向对象软件的元素”的原始书中,它说可以使用观察者模式来实现中介器模式。但是,也可以通过让同事(大致相当于观察者模式的主题)引用对Mediator类或Mediator接口的引用来实现。
在许多情况下,当您想使用观察者模式时,它们的关键是一个对象不应该知道其他对象正在观察其状态。
调解器更为具体,它避免让类直接进行通信,而是通过调解器进行通信。通过允许将通信卸载到只处理通信的类,这有助于单一职责原则。
一个经典的Mediator示例是在GUI中,其中,幼稚的方法可能会导致按钮单击事件中的代码显示为“如果Foo面板被禁用并且Bar面板上有一个标签为“ Please enter date”的标签,请不要调用服务器,否则,继续前进”,如果使用Mediator模式,它可能会说“我只是一个按钮,对Foo面板和Bar面板上的标签一无所知,所以我只想问我的中介者是否呼叫服务器现在可以。”
或者,如果使用观察者模式实现调解器,该按钮将显示“嘿,观察者(其中包括调解器),我的状态发生了变化(有人点击了我。如果有需要,可以做点什么”)。在我的示例中,这可能比直接引用中介程序更没有意义,但是在许多情况下,使用Observer模式实现Mediator会有意义,并且Observer和Mediator之间的差异不仅仅是代码本身的差异,也是意图之一。
客户1:嗨,主题,您何时更改?
客户2:您何时更改主题?我没有注意到!
Client3:我知道主题已更改。
让我们举一个例子:考虑要构建两个应用程序:
构建聊天应用程序,您将选择mediator
设计模式。
为什么我们会更喜欢mediator
?看看它的定义:
通过中介者模式,对象之间的通信被封装在中介者对象中。对象不再彼此直接通信,而是通过调解器进行通信。这减少了通信对象之间的依赖性,从而减少了耦合。
魔术如何运作?首先,我们将创建聊天介体,并使人员对象注册到该介体,因此它与每个人都有两个定向连接(该人可以使用聊天介体发送消息,因为它可以访问它,而聊天介体可以访问人对象的接收方法,因为他也可以访问它)
function Person(name) {
let self = this;
this._name = name;
this._chat = null;
this._receive(from, message) {
console.log("{0}: '{1}'".format(from.name(), message));
}
this._send(to, message) {
this._chat.message(this, to, message);
}
return {
receive: (from, message) => { self._receive(from, message) },
send: (to, message) => { self._send(to, message) },
initChat: (chat) => { this._chat = chat; },
name: () => { return this._name; }
}
}
function ChatMediator() {
let self = this;
this._persons = [];
return {
message: function (from, to, message) {
if (self._persons.indexOf(to) > -1) {
self._persons[to].receive(from, message);
}
},
register: function (person) {
person.initChat(self);
self._persons.push(person);
}
unRegister: function (person) {
person.initChat(null);
delete self._persons[person.name()];
}
}
};
//Usage:
let chat = new ChatMediator();
let colton = new Person('Colton');
let ronan = new Person('Ronan');
chat.register(colton);
chat.register(ronan);
colton.send(colton, 'Hello there, nice to meet you');
ronan.send(ronan, 'Nice to meet you to');
colton.send(colton, 'Goodbye!');
chat.unRegister(colton);
构建911呼叫应用程序时,您将选择observer
设计模式。
observer
对象都希望在发生紧急状态时得到通知,以便他能开车出门并提供帮助。observable
随时参考每辆救护车observers
,并在需要帮助(或产生事件)时通知他们。为什么我们会更喜欢observer
?看看它的定义:
一个称为主题的对象会维护其依赖项的列表,即观察者,并通常通过调用其方法之一来自动将状态更改通知他们。
function AmbulanceObserver(name) {
let self = this;
this._name = name;
this._send(address) {
console.log(this._name + ' has been sent to the address: ' + address);
}
return {
send: (address) => { self._send(address) },
name: () => { return this._name; }
}
}
function OperatorObservable() {
let self = this;
this._ambulances = [];
return {
send: function (ambulance, address) {
if (self._ambulances.indexOf(ambulance) > -1) {
self._ambulances[ambulance].send(address);
}
},
register: function (ambulance) {
self._ambulances.push(ambulance);
}
unRegister: function (ambulance) {
delete self._ambulances[ambulance.name()];
}
}
};
//Usage:
let operator = new OperatorObservable();
let amb111 = new AmbulanceObserver('111');
let amb112 = new AmbulanceObserver('112');
operator.register(amb111);
operator.register(amb112);
operator.send(amb111, '27010 La Sierra Lane Austin, MN 000');
operator.unRegister(amb111);
operator.send(amb112, '97011 La Sierra Lane Austin, BN 111');
operator.unRegister(amb112);
mediator
在人员对象之间进行双向通讯(发送和接收),而操作员observable
只有一种双向通讯(它告诉救护车observer
驾驶并完成)。mediator
可使人对象在他们之间进行交互(即使不是直接通信),救护车也observers
仅记录操作员observable
事件。mediator
还mediator
保留了对每个人的引用。如果救护车observer
不能参照操作人员observable
,则只有驾驶员observable
可以参照每个救护车observer
。尽管它们都是用于组织状态变化的方式,但在结构和语义上与IMO略有不同。
观察者用于从对象本身广播特定对象的状态更改。因此,更改发生在还负责发出信号的中央对象中。但是,在调解器中,状态更改可以在任何对象中发生,但是状态更改是通过调解器广播的。因此,流程有所不同。但是,我认为这不会影响我们的代码行为。我们可以使用一个或另一个来实现相同的行为。另一方面,这种差异可能会对代码的概念理解产生一些影响。
可见,使用模式的主要目的是在开发人员之间创建通用语言。因此,当我看到调解人时,我个人理解尝试通过单个代理/集线器进行通信以减少通信噪音(或促进SRP)的多个元素,并且每个对象在具有发出状态更改信号的能力方面同样重要。例如,考虑有多架飞机接近机场。每个人都应该通过定向塔(调解人)进行交流,而不是相互交流。(以为有1000架飞机在降落时互相通信-太混乱了)
但是,当我看到观察者时,这意味着我可能会担心某些状态更改,因此应该注册/订阅以侦听特定的状态更改。有一个中央对象负责发出状态更改信号。例如,如果我在关心从A到B途中的特定机场,我可以注册到该机场以捕获广播的某些事件,例如,如果有空跑道或类似的跑道。
希望清楚。
@cdc很好地解释了意图上的差异。
我将在上面添加更多信息。
观察者:允许将一个对象中的事件通知给不同的对象集(不同类的实例)
介体:集中从特定类创建的对象集之间的通信。
来自工厂的中介者模式的结构:
介体:定义同事之间的交流接口。
同事:是一个抽象类,它定义要在同事之间交流的事件
ConcreteMediator:通过协调同事对象并维护其同事来实现合作行为
ConcreteColleague:实现由Mediator接收的通知操作,该通知操作是由其他同事生成的
一个真实的例子:
您正在以网状拓扑维护计算机网络。如果添加了新计算机或删除了现有计算机,则该网络中的所有其他计算机都应该知道这两个事件。
让我们看看介体模式如何适应它。
程式码片段:
import java.util.List;
import java.util.ArrayList;
/* Define the contract for communication between Colleagues.
Implementation is left to ConcreteMediator */
interface Mediator{
public void register(Colleague colleague);
public void unregister(Colleague colleague);
}
/* Define the contract for notification events from Mediator.
Implementation is left to ConcreteColleague
*/
abstract class Colleague{
private Mediator mediator;
private String name;
public Colleague(Mediator mediator,String name){
this.mediator = mediator;
this.name = name;
}
public String toString(){
return name;
}
public abstract void receiveRegisterNotification(Colleague colleague);
public abstract void receiveUnRegisterNotification(Colleague colleague);
}
/* Process notification event raised by other Colleague through Mediator.
*/
class ComputerColleague extends Colleague {
private Mediator mediator;
public ComputerColleague(Mediator mediator,String name){
super(mediator,name);
}
public void receiveRegisterNotification(Colleague colleague){
System.out.println("New Computer register event with name:"+colleague+
": received @"+this);
// Send further messages to this new Colleague from now onwards
}
public void receiveUnRegisterNotification(Colleague colleague){
System.out.println("Computer left unregister event with name:"+colleague+
":received @"+this);
// Do not send further messages to this Colleague from now onwards
}
}
/* Act as a central hub for communication between different Colleagues.
Notifies all Concrete Colleagues on occurrence of an event
*/
class NetworkMediator implements Mediator{
List<Colleague> colleagues = new ArrayList<Colleague>();
public NetworkMediator(){
}
public void register(Colleague colleague){
colleagues.add(colleague);
for (Colleague other : colleagues){
if ( other != colleague){
other.receiveRegisterNotification(colleague);
}
}
}
public void unregister(Colleague colleague){
colleagues.remove(colleague);
for (Colleague other : colleagues){
other.receiveUnRegisterNotification(colleague);
}
}
}
public class MediatorPatternDemo{
public static void main(String args[]){
Mediator mediator = new NetworkMediator();
ComputerColleague colleague1 = new ComputerColleague(mediator,"Eagle");
ComputerColleague colleague2 = new ComputerColleague(mediator,"Ostrich");
ComputerColleague colleague3 = new ComputerColleague(mediator,"Penguin");
mediator.register(colleague1);
mediator.register(colleague2);
mediator.register(colleague3);
mediator.unregister(colleague1);
}
}
输出:
New Computer register event with name:Ostrich: received @Eagle
New Computer register event with name:Penguin: received @Eagle
New Computer register event with name:Penguin: received @Ostrich
Computer left unregister event with name:Eagle:received @Ostrich
Computer left unregister event with name:Eagle:received @Penguin
说明:
Programmers.StackExchange
被拒绝,但是我在那里发表了类似的帖子,因为我对答案感兴趣。您可能会发现一些有趣的答案。:)