📄 pat5e.htm
字号:
There's no need to define an abstract Mediator class when colleagueswork with only one mediator. The abstract coupling that theMediator class provides lets colleagues work with different Mediatorsubclasses, and vice versa.</LI><A NAME="auto1051"></A><P></P><A NAME="media-comm-coll"></A><LI><EM>Colleague-Mediator communication.</EM>Colleagues have to communicate with their mediator when an event ofinterest occurs. One approach is to implement the Mediator as anObserver using the <A HREF="pat5gfs.htm" TARGET="_mainDisplayFrame">Observer (293)</A> pattern. Colleagueclasses act as Subjects, sending notifications to the mediatorwhenever they change state. The mediator responds by propagating theeffects of the change to other colleagues.<A NAME="deleg-278"></A><A NAME="smalltkv-use-media"></A><P>Another approach defines a specialized notification interface inMediator that lets colleagues be more direct in their communication.Smalltalk/V for Windows uses a form of delegation: When communicatingwith the mediator, a colleague passes itself as an argument, allowingthe mediator to identify the sender. The Sample Code uses thisapproach, and the Smalltalk/V implementation is discussed further inthe Known Uses.</P></LI></OL><A NAME="samplecode"></A><H2><A HREF="#knownuses"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Known Uses"></A> Sample Code</H2> <A NAME="auto1052"></A><P>We'll use a DialogDirector to implement the font dialog box shown inthe Motivation. The abstract class <CODE>DialogDirector</CODE> definesthe interface for directors.</P><A NAME="auto1053"></A><PRE> class DialogDirector { public: virtual ~DialogDirector(); virtual void ShowDialog(); virtual void WidgetChanged(Widget*) = 0; protected: DialogDirector(); virtual void CreateWidgets() = 0; };</PRE><A NAME="widget-class"></A><P><CODE>Widget</CODE> is the abstract base class for widgets. Awidget knows its director.</P><A NAME="auto1054"></A><PRE> class Widget { public: Widget(DialogDirector*); virtual void Changed(); virtual void HandleMouse(MouseEvent& event); // ... private: DialogDirector* _director; };</PRE><A NAME="auto1055"></A><P><CODE>Changed</CODE> calls the director's <CODE>WidgetChanged</CODE>operation. Widgets call <CODE>WidgetChanged</CODE> on their director toinform it of a significant event.</P><A NAME="auto1056"></A><PRE> void Widget::Changed () { _director->WidgetChanged(this); }</PRE><A NAME="auto1057"></A><P>Subclasses of <CODE>DialogDirector</CODE> override<CODE>WidgetChanged</CODE> to affect the appropriate widgets. The widgetpasses a reference to itself as an argument to <CODE>WidgetChanged</CODE>to let the director identify the widget that changed.<CODE>DialogDirector</CODE> subclasses redefine the<CODE>CreateWidgets</CODE> pure virtual to construct the widgets in thedialog.</P><A NAME="listbox2"></A><P>The <CODE>ListBox</CODE>, <CODE>EntryField</CODE>, and <CODE>Button</CODE> aresubclasses of <CODE>Widget</CODE> for specialized user interfaceelements. <CODE>ListBox</CODE> provides a <CODE>GetSelection</CODE>operation to get the current selection, and <CODE>EntryField</CODE>'s<CODE>SetText</CODE> operation puts new text into the field.</P><A NAME="auto1058"></A><PRE> class ListBox : public Widget { public: ListBox(DialogDirector*); virtual const char* GetSelection(); virtual void SetList(List<char*>* listItems); virtual void HandleMouse(MouseEvent& event); // ... }; class EntryField : public Widget { public: EntryField(DialogDirector*); virtual void SetText(const char* text); virtual const char* GetText(); virtual void HandleMouse(MouseEvent& event); // ... };</PRE><A NAME="auto1059"></A><P><CODE>Button</CODE> is a simple widget that calls <CODE>Changed</CODE>whenever it's pressed. This gets done in its implementation of<CODE>HandleMouse</CODE>:</P><A NAME="auto1060"></A><PRE> class Button : public Widget { public: Button(DialogDirector*); virtual void SetText(const char* text); virtual void HandleMouse(MouseEvent& event); // ... }; void Button::HandleMouse (MouseEvent& event) { // ... Changed(); }</PRE><A NAME="auto1061"></A><P>The <CODE>FontDialogDirector</CODE> class mediates between widgets in thedialog box. <CODE>FontDialogDirector</CODE> is a subclass of<CODE>DialogDirector</CODE>:</P><A NAME="auto1062"></A><PRE> class FontDialogDirector : public DialogDirector { public: FontDialogDirector(); virtual ~FontDialogDirector(); virtual void WidgetChanged(Widget*); protected: virtual void CreateWidgets(); private: Button* _ok; Button* _cancel; ListBox* _fontList; EntryField* _fontName; };</PRE><A NAME="auto1063"></A><P><CODE>FontDialogDirector</CODE> keeps track of the widgets it displays. Itredefines<CODE>CreateWidgets</CODE> to create the widgets and initialize itsreferences to them:</P><A NAME="auto1064"></A><PRE> void FontDialogDirector::CreateWidgets () { _ok = new Button(this); _cancel = new Button(this); _fontList = new ListBox(this); _fontName = new EntryField(this); // fill the listBox with the available font names // assemble the widgets in the dialog }</PRE><A NAME="auto1065"></A><P><CODE>WidgetChanged</CODE> ensures that the widgets work together properly:</P><A NAME="auto1066"></A><PRE> void FontDialogDirector::WidgetChanged ( Widget* theChangedWidget ) { if (theChangedWidget == _fontList) { _fontName->SetText(_fontList->GetSelection()); } else if (theChangedWidget == _ok) { // apply font change and dismiss dialog // ... } else if (theChangedWidget == _cancel) { // dismiss dialog } }</PRE><A NAME="auto1067"></A><P>The complexity of <CODE>WidgetChanged</CODE> increases proportionallywith the complexity of the dialog. Large dialogs are undesirable forother reasons, of course, but mediator complexity might mitigate thepattern's benefits in other applications.</P><A NAME="knownuses"><A><H2><A HREF="#relatedpatterns"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Related Patterns"></A> Known Uses</H2> <A NAME="auto1068"></A><P>Both ET++ [<A HREF="bibfs.htm#et++" TARGET="_mainDisplayFrame">WGM88</A>] and the THINK C class library [<A HREF="bibfs.htm#think" TARGET="_mainDisplayFrame">Sym93b</A>] usedirector-like objects in dialogs as mediators between widgets.</P><A NAME="smalltkv-use-media2"></A><A NAME="viewmanager"></A><P>The application architecture of Smalltalk/V for Windows is based on amediator structure [<A HREF="bibfs.htm#lalonde_st" TARGET="_mainDisplayFrame">LaL94</A>]. In that environment, anapplication consists of a Window containing a set of panes. Thelibrary contains several predefined Pane objects; examples includeTextPane, ListBox, Button, and so on.These panes can be used without subclassing. An application developeronly subclasses from ViewManager, a class that's responsible for doinginter-pane coordination. ViewManager is the Mediator, and each paneonly knows its view manager, which is considered the "owner" of thepane. Panes don't refer to each other directly.</P><A NAME="auto1069"></A><P>The following object diagram shows a snapshot of an application atrun-time:</P><A NAME="viewman-281o"></A><P ALIGN=CENTER><IMG SRC="Pictures/media032.gif"></P><A NAME="auto1070"></A><P>Smalltalk/V uses an event mechanism for Pane-ViewManagercommunication. A pane generates an event when it wants to getinformation from the mediator or when it wants to inform the mediatorthat something significant happened. An event defines a symbol (e.g.,<CODE>#select</CODE>) that identifies the event. To handle the event, theview manager registers a method selector with the pane. This selectoris the event's handler; it will be invoked whenever the event occurs.</P><A NAME="auto1071"></A><P>The following code excerpt shows how a ListPane object gets created insidea ViewManager subclass and how ViewManager registers an event handlerfor the <CODE>#select</CODE> event:</P><A NAME="auto1072"></A><PRE> self addSubpane: (ListPane new paneName: 'myListPane'; owner: self; when: #select perform: #listSelect:).</PRE><A NAME="auto1073"></A><P>Another application of the Mediator pattern is in coordinating complexupdates. An example is the ChangeManager class mentioned in<A HREF="pat5gfs.htm" TARGET="_mainDisplayFrame">Observer (293)</A>. ChangeManager mediates betweensubjects and observers to avoid redundant updates. When an objectchanges, it notifies the ChangeManager, which in turn coordinates theupdate by notifying the object's dependents.</P><A NAME="unidraw-use-media"></A><P>A similar application appears in the Unidraw drawingframework [<A HREF="bibfs.htm#unidraw_framework" TARGET="_mainDisplayFrame">VL90</A>] and uses a class called CSolver toenforce connectivity constraints between "connectors." Objects ingraphical editors can appear to stick to one another in differentways. Connectors are useful in applications that maintainconnectivity automatically, like diagram editors and circuit designsystems. CSolver is a mediator between connectors. It solves theconnectivity constraints and updates the connectors' positions toreflect them.</P><A NAME="relatedpatterns"></A><H2><A HREF="#last"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: navigation"></A> Related Patterns</H2> <A NAME="auto1074"></A><P><A HREF="pat4efs.htm" TARGET="_mainDisplayFrame">Facade (185)</A> differsfrom Mediator in that it abstracts a subsystem of objects to providea more convenient interface. Its protocol is unidirectional; thatis, Facade objects make requests of the subsystem classes but notvice versa. In contrast, Mediator enables cooperative behaviorthat colleague objects don't or can't provide, and the protocol ismultidirectional.</P><A NAME="media-comm-coll2"></A><P>Colleagues can communicate with the mediator using the <AHREF="pat5gfs.htm" TARGET="_mainDisplayFrame">Observer (293)</A> pattern.</P><A NAME="last"></A><P><A HREF="#intent"><IMG SRC="gifsb/up3.gif" BORDER=0></A><BR><A HREF="pat5ffs.htm" TARGET="_mainDisplayFrame"><IMG SRC="gifsb/rightar3.gif" ALIGN=TOP BORDER=0></A> <A HREF="pat5ffs.htm" TARGET="_mainDisplayFrame">Memento</A><BR><A HREF="pat5dfs.htm" TARGET="_mainDisplayFrame"><IMG SRC="gifsb/leftarr3.gif" ALIGN=TOP BORDER=0></A> <A HREF="pat5dfs.htm" TARGET="_mainDisplayFrame">Iterator</A></P></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -