Sono nuovo per progettare modelli, ecco un classico esempio di modello di mediatore di base che ha 3 problemi con esso, prima di tutto guarda l'immagine dell'applicazione, il diagramma, il codice e la descrizione:
Utilizziamo DialogDirector
per implementare la finestra di dialogo dei caratteri mostrata nella motivazione. La classe astratta DialogDirector
definisce l'interfaccia per i director.
class DialogDirector {
public:
virtual ~DialogDirector();
virtual void ShowDialog();
virtual void WidgetChanged(Widget*) = 0;
protected:
DialogDirector();
virtual void CreateWidgets() = 0;
};
Widget
è la classe base astratta per i widget. Un widget conosce il suo direttore.
class Widget {
public:
Widget(DialogDirector*);
virtual void Changed();
virtual void HandleMouse(MouseEvent& event);
// ...
private:
DialogDirector* _director;
};
Changed chiama l'operazione WidgetChanged
del regista. I widget chiamano WidgetChanged
sul loro direttore per informarlo di un evento significativo.
void Widget::Changed () {
_director->WidgetChanged(this);
}
Sottoclassi di DialogDirector
override WidgetChanged
per influenzare i widget appropriati. Il widget passa un riferimento a se stesso come argomento a WidgetChanged
per consentire al director di identificare il widget modificato. DialogDirector
sottoclassi ridefiniscono il CreateWidgets
puro virtuale per costruire i widget nella finestra di dialogo.
ListBox
, EntryField
e Button
sono sottoclassi di Widget
per elementi di interfaccia utente specializzati. ListBox
fornisce un'operazione GetSelection
per ottenere la selezione corrente e l'operazione EntryField
SetText
inserisce un nuovo testo nel campo.
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
è un semplice widget che chiama Changed
ogni volta che viene premuto. Questo viene fatto nella sua implementazione di 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();
}
La classe FontDialogDirector
media tra i widget nella finestra di dialogo. FontDialogDirector
è una sottoclasse di 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
tiene traccia dei widget visualizzati. Ridefinisce CreateWidgets
per creare i widget e inizializzarne i riferimenti:
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
garantisce che i widget funzionino correttamente:
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
}
}
Quando voglio aggiungere un altro widget, devo affrontare 3 problemi:
- Devo aggiungere
MyNewWidget
class. (non è un problema) - Devo modificare l'implementazione della classe
FontDialogDirector
e aggiungereMyNewWidget* _myNewWidget;
. - Aggiungi
_myNewWidget= new MyNewWidget(this);
- Modifica l'implementazione del metodo
WidgetChanged
e aggiungielse if (theChangedWidget == _myNewWidget) //...
ad essa.
C'è qualche soluzione che non ho nel codice, quando arriva un nuovo widget?