Читать «Применение Windows API» онлайн - страница 21
А. И. Легалов
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 или посмотреть Patterns Home Page (домашнюю страницу образцов). Там описано много творческих способов использования полиморфизма, наследования и шаблонизации, чтобы делать программное обеспечение более пригодным для многократного использования.