I am new to design patterns, here is a classic example of basic mediator pattern that has 3 problems with it, first of all take a look at the application image, diagram, code and description:
We use a DialogDirector
to implement the font dialog box shown in the Motivation. The abstract class DialogDirector
defines the interface for directors.
class DialogDirector {
public:
virtual ~DialogDirector();
virtual void ShowDialog();
virtual void WidgetChanged(Widget*) = 0;
protected:
DialogDirector();
virtual void CreateWidgets() = 0;
};
Widget
is the abstract base class for widgets. A widget knows its director.
class Widget {
public:
Widget(DialogDirector*);
virtual void Changed();
virtual void HandleMouse(MouseEvent& event);
// ...
private:
DialogDirector* _director;
};
Changed calls the director's WidgetChanged
operation. Widgets call WidgetChanged
on their director to inform it of a significant event.
void Widget::Changed () {
_director->WidgetChanged(this);
}
Subclasses of DialogDirector
override WidgetChanged
to affect the appropriate widgets. The widget passes a reference to itself as an argument to WidgetChanged
to let the director identify the widget that changed. DialogDirector
subclasses redefine the CreateWidgets
pure virtual to construct the widgets in the dialog.
The ListBox
, EntryField
, and Button
are subclasses of Widget
for specialized user interface elements. ListBox
provides a GetSelection
operation to get the current selection, and EntryField
's SetText
operation puts new text into the field.
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);
// ...
};
Button
is a simple widget that calls Changed
whenever it's pressed. This gets done in its implementation of HandleMouse
:
class Button : public Widget {
public:
Button(DialogDirector*);
virtual void SetText(const char* text);
virtual void HandleMouse(MouseEvent& event);
// ...
};
void Button::HandleMouse (MouseEvent& event) {
// ...
Changed();
}
The FontDialogDirector
class mediates between widgets in the dialog box. FontDialogDirector
is a subclass of DialogDirector
:
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;
};
FontDialogDirector
keeps track of the widgets it displays. It redefines CreateWidgets
to create the widgets and initialize its references to them:
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
}
WidgetChanged
ensures that the widgets work together properly:
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
}
}
When I want to add one more widget, I have to deal with 3 problems:
- I need to add
MyNewWidget
class. (it's not a problem) - I need to change the
FontDialogDirector
class implementation and addMyNewWidget* _myNewWidget;
. - Add
_myNewWidget= new MyNewWidget(this);
- Change the
WidgetChanged
method implementation, and addelse if (theChangedWidget == _myNewWidget) //...
to it.
Is there any solution that I don't have to hard code, when a new widget arrives?
fontListbox
changes, it has to say to other widgets that I was changed, so theentryField
changes it's text and other widgets may do different activities. here with mediator, all widgets talk to one class and it isfontDialogDirector
that handles the interactionstextbox
,listbox
andButton
that should have to communicate each other, in order to let themselves to be aware of what is happening there and after that, others can change their properties to provide some validation here.