⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pat5e.htm

📁 设计模式英文版 作者:Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides 四人帮的书。 学设计模式的必读的书籍!经典中的经典
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<P></P>

<A NAME="media-comm-coll"></A>
<LI><EM>Colleague-Mediator communication.</EM>
Colleagues have to communicate with their mediator when an event of
interest occurs.  One approach is to implement the Mediator as an
Observer using the <A HREF="pat5gfs.htm" TARGET="_mainDisplayFrame">Observer&nbsp;(293)</A> pattern.  Colleague
classes act as Subjects, sending notifications to the mediator
whenever they change state.  The mediator responds by propagating the
effects 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 in
Mediator that lets colleagues be more direct in their communication.
Smalltalk/V for Windows uses a form of delegation: When communicating
with the mediator, a colleague passes itself as an argument, allowing
the mediator to identify the sender.  The Sample Code uses this
approach, and the Smalltalk/V implementation is discussed further in
the Known Uses.</P>

</LI>

</OL>

<A NAME="samplecode"></A>
<H2><A HREF="#knownuses"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Sample Code</H2> 

<A NAME="auto1052"></A>
<P>We'll use a DialogDirector to implement the font dialog box shown in
the Motivation.  The abstract class <CODE>DialogDirector</CODE> defines
the 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.  A
widget knows its director.</P>

<A NAME="auto1054"></A>
<PRE>
    class Widget {
    public:
        Widget(DialogDirector*);
        virtual void Changed();
    
        virtual void HandleMouse(MouseEvent&amp; 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 to
inform 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 widget
passes 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 the
dialog.</P>

<A NAME="listbox2"></A>
<P>The <CODE>ListBox</CODE>, <CODE>EntryField</CODE>, and <CODE>Button</CODE> are
subclasses of <CODE>Widget</CODE> for specialized user interface
elements. <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&amp; event);
        // ...
    };
    
    class EntryField : public Widget {
    public:
        EntryField(DialogDirector*);
    
        virtual void SetText(const char* text);
        virtual const char* GetText();
        virtual void HandleMouse(MouseEvent&amp; 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&amp; event);
        // ...
    };
    
    void Button::HandleMouse (MouseEvent&amp; event) {
        // ...
        Changed();
    }
</PRE>

<A NAME="auto1061"></A>
<P>The <CODE>FontDialogDirector</CODE> class mediates between widgets in the
dialog 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.  It
redefines
<CODE>CreateWidgets</CODE> to create the widgets and initialize its
references 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 proportionally
with the complexity of the dialog.  Large dialogs are undesirable for
other reasons, of course, but mediator complexity might mitigate the
pattern's benefits in other applications.</P>

<A NAME="knownuses"><A>
<H2><A HREF="#relatedpatterns"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Known Uses</H2> 

<A NAME="auto1068"></A>
<P>Both ET++&nbsp;[<A HREF="vfs.htm?doc=bib-0.htm&fid=bb&hid=et++" TARGET="_mainDisplayFrame">WGM88</A>] and the THINK C class library&nbsp;[<A HREF="vfs.htm?doc=bib-0.htm&fid=bb&hid=think" TARGET="_mainDisplayFrame">Sym93b</A>] use
director-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 a
mediator structure&nbsp;[<A HREF="vfs.htm?doc=bib-0.htm&fid=bb&hid=lalonde_st" TARGET="_mainDisplayFrame">LaL94</A>]. In that environment, an
application consists of a Window containing a set of panes.  The
library contains several predefined Pane objects; examples include
TextPane, ListBox, Button, and so on.
These panes can be used without subclassing.  An application developer
only subclasses from ViewManager, a class that's responsible for doing
inter-pane coordination. ViewManager is the Mediator, and each pane
only knows its view manager, which is considered the "owner" of the
pane.  Panes don't refer to each other directly.</P>

<A NAME="auto1069"></A>
<P>The following object diagram shows a snapshot of an application at
run-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-ViewManager
communication.  A pane generates an event when it wants to get
information from the mediator or when it wants to inform the mediator
that something significant happened.  An event defines a symbol (e.g.,
<CODE>#select</CODE>) that identifies the event. To handle the event, the
view manager registers a method selector with the pane.  This selector
is 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 inside
a ViewManager subclass and how ViewManager registers an event handler
for 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 complex
updates.  An example is the ChangeManager class mentioned in
<A HREF="pat5gfs.htm" TARGET="_mainDisplayFrame">Observer&nbsp;(293)</A>.  ChangeManager mediates between
subjects and observers to avoid redundant updates.  When an object
changes, it notifies the ChangeManager, which in turn coordinates the
update by notifying the object's dependents.</P>

<A NAME="unidraw-use-media"></A>
<P>A similar application appears in the Unidraw drawing
framework&nbsp;[<A HREF="vfs.htm?doc=bib-0.htm&fid=bb&hid=unidraw_framework" TARGET="_mainDisplayFrame">VL90</A>] and uses a class called CSolver to
enforce connectivity constraints between "connectors." Objects in
graphical editors can appear to stick to one another in different
ways.  Connectors are useful in applications that maintain
connectivity automatically, like diagram editors and circuit design
systems.  CSolver is a mediator between connectors.  It solves the
connectivity constraints and updates the connectors' positions to
reflect them.</P>

<A NAME="relatedpatterns"></A>
<H2><A HREF="#last"><IMG SRC="gifsb/down3.gif" BORDER=0></A> Related Patterns</H2> 

<A NAME="auto1074"></A>
<P><A HREF="pat4efs.htm" TARGET="_mainDisplayFrame">Facade&nbsp;(185)</A> differs
from Mediator in that it abstracts a subsystem of objects to provide
a more convenient interface.  Its protocol is unidirectional; that
is, Facade objects make requests of the subsystem classes but not
vice versa.  In contrast, Mediator enables cooperative behavior
that colleague objects don't or can't provide, and the protocol is
multidirectional.</P>

<A NAME="media-comm-coll2"></A>
<P>Colleagues can communicate with the mediator using the <A
HREF="pat5gfs.htm" TARGET="_mainDisplayFrame">Observer&nbsp;(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 + -