Окно диалога
Страница 7. Фабрика объектов


 

Фабрика объектов

Во-вторых, Windows имеет неудачную идею (привычку) посылать сообщения WM_COMMAND и WM_NOTIFY перед WM_INITDIALOG и после WM_DESTROY. Что можно здесь сказать? Я бы побил менеджера, который ответствен за эти дела. Но раз это есть, мы должны защитить себя, проверяя, является ли ctrl ненулевым перед вызовом OnCommand и OnNotify.

BOOL CALLBACK ModalDialog::ModalDialogProc (HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
DlgController * ctrl = GetWinLong<DlgController *> (hwnd);
switch (message)
{
case WM_INITDIALOG:
{
CtrlFactory *ctrlFactory =
reinterpret_cast<CtrlFactory *> (lParam);
ctrl = ctrlFactory->MakeController (hwnd);
SetWinLong<DlgController *> (hwnd, ctrl);
ctrl->OnInitDialog (hwnd);
}
return TRUE;

case WM_COMMAND:
if (ctrl && ctrl->
OnCommand (hwnd, LOWORD(wParam), HIWORD (wParam)))
return TRUE;
break;

case WM_NOTIFY:
if (ctrl && ctrl->OnNotify (hwnd, wParam, (NMHDR *)lParam))
return TRUE;
break;

case WM_DESTROY:
delete ctrl;
SetWinLong<DlgController *> (hwnd, 0);
break;
}
return FALSE;
}

Здесь представлена красота полиморфизма в действии. Объект фабрики создан клиентом, использующим шаблонный класс. Этот объект передается конструктору ModalDialog. ModalDialog передает его процедуре диалога как пустой указатель (дело в том, что он должен пройти через Windows). Процедура Диалога получает его внутри сообщения WM_INITDIALOG как LPARAM. После прохождения пищеварительного тракта Windows он должен быть восстановлен к своей первоначальной форме, переводом его обратно к указателю на CtrlFactory - в базовый класс всех фабрик контроллера.

Когда мы вызываем его виртуальный метод MakeController, мы вызываем метод, переопределенный в шаблонном классе ControllerFactory. Он создает новый объект для класса ActualCtrl, определенного клиентом. Но снова, он возвращает этот объект к нам замаскированный как обобщенный указатель на DlgController. Так всякий раз, когда мы вызываем любой из виртуальных методов ctrl, мы выполняем клиентские переопределения, определенные в классе ActualCtrl. Это лучшее проявление полиморфизма: Вы записываете код, используя обобщенные указатели, но когда код выполнен, он вызывается с очень специфическими указателями. Когда Вы вызываете методы через эти указатели, Вы выполняете специфические методы, обеспеченные клиентом вашего кода.

Вот, что случается с фабрикой объектов, чей фактический класс
ControllerFactory < EditorCtrl, EditorData >

Передается конструктору ModalDialog как

void *

Передася от Windows к ModalDialogProcedure как

LPARAM

Приведение в ModalDialogProcedure к

CtrlFactory *

А вот, что случается с объектными данными, чьим фактическим классом является EditorData.

Передается конструктору фабрики как void *
Приведение в методе AcquireController класса ControllerFactory < EditorCtrl, EditorData > к EditorData *
Переданный конструктору EditCtrl как EditotData *

Объект класса EditCtrl, созданный в методе MakeController класса ControllerFactory < EditorCtrl, EditorData > возвращается из него как DlgController * и сохраняется в этой форме как статический член данных ModalDialog.

Если Вы имеете проблемы после моего объяснения, не отчаивайтесь. Объектно ориентированные методы, которые я только описал, трудны, но необходимы. Они названы образцами проектирования. Я настоятельно рекомендую читать книгу: Gamma, Helm, Johnson and Vlissides - Design Patterns, Elements of Reusable Object-Oriented Software.

 
« Предыдущая статья   Следующая статья »