MFC Лучшая практика и модульность

В MFC некоторые предоставляемые механизмы позволяют программисту обходить модульность, инкапсуляцию и сокрытие информации, что является аргументом в пользу наиболее желательных особенностей объектно-ориентированной среды.

Один (из многих) примеров — элементы управления, нарисованные владельцем:
Вы можете выбрать либо реализовать DrawItem в подклассе дочернего элемента управления и выполняйте все рисунки этого элемента управления в этом подклассе, делая его более модульным:

class CustomButton: CButton{
// --- Lots of stuff, DECLARE_DYNAMIC etc

virtual void DrawItem(LPDRAWITEMSTRUCT lpdis){
// Drawing code for this button in the button's subclass
}
};

…или вы можете выбрать ручку WM_DRAWITEM сообщение в родительском классе Window через OnDrawItem

class MainFrame: CFrameWnd{
// --- Lots of stuff, DECLARE_DYNAMIC etc

CustomButton button;

afx_msg void OnDrawItem(LPDRAWITEMSTRUCT lpdis, UINT id){

if(id == CUSTOM_BUTTON_ID){
// Drawing code for this button in the button's subclass
}
}
};

В более поздней ситуации рисунок элемента управления находится за пределами подкласса элемента управления, что означает, что «ООП структуры данных, как правило, носят с собой своих собственных операторов» подорвано .. верно?

Поэтому мой вопрос: какой из них считается «лучшей практикой»? Должна быть причина, по которой существует вторая, — может ли кто-нибудь предложить обстоятельства, при которых подрыв модульности был бы лучшим вариантом?

0

Решение

Этот вопрос, кажется, задает вопрос, когда разумно иметь родительский объект, который содержит один или несколько дочерних объектов для обработки сообщений, предназначенных для дочернего объекта, а не просто передавать сообщение дочернему объекту, позволяя дочернему объекту обрабатывать его.

Конкретный пример — с классами окон MFC, в которых объект окна, который содержит другие объекты окна (в данном случае кнопку), обрабатывает сообщение рисования, а не просто передает сообщение дочернему элементу для обработки.

Основной ответ будет, это зависит. Могут быть случаи, когда вы создаете объект окна и как часть этого вы перебираете поведение рисования дочерних элементов управления, чтобы изменить внешний вид дочерних элементов управления. Например, если у вас есть набор кнопок, внешний вид которых вы хотите изменить в зависимости от информации в родительском окне, вы можете переместить рисунок дочерних элементов управления, чтобы изменить внешний вид.

Это было бы аналогично наличию объекта кнопки, который допускает несколько различных типов внешнего вида, позволяя родительскому окну предоставлять объект рисования дочернему элементу управления. Результатом будет то, что у дочернего элемента будет поведение при рисовании по умолчанию, которое родитель будет перебирать, предоставляя объект рисования.

Видеть это статья в википедии о шаблоне стратегии или это статья о шаблоне стратегии с боковыми ссылками для других шаблонов который дает краткое обсуждение такого рода проблем программирования. Другим примером может быть Схема цепочки ответственности.

В этом конкретном примере вместо того, чтобы родительский объект предоставлял объект описания чертежа для использования дочерним объектом, родительский объект просто перехватывает сообщения рисования и выполняет сам рисунок.

Если изменение внешнего вида дочернего элемента управления может быть выполнено без влияния на другие функции дочернего элемента управления, это не будет плохим подходом, хотя это может сбить с толку программиста, выполняющего техническое обслуживание или другие изменения. Однако такого рода поведение переопределения может быть замечено в других случаях, таких как отсечение окна, в котором рисунок некоторого компонента окна отсечен так, что любая часть компонента, которая была бы вне области окна, не прорисована.

Таким образом, подход, заключающийся в том, что родительский объект перехватывает и обрабатывает сообщения, нацеленные на дочерний объект родителя, обеспечивает большую гибкость, позволяя различным родителям изменять определенное поведение ребенка в зависимости от того, чего хочет достичь родитель.

Однако эта гибкость имеет свою цену.

1

Другие решения

Было бы неоптимальным ООП, если бы во второй ситуации CUSTOM_BUTTON_ID представлял собой некоторые данные, используемые внутренним элементом управления. Это нарушило бы концепцию сокрытия информации, определенную Дэвидом Парнасом (http://www.cs.umd.edu/class/spring2003/cmsc838p/Design/criteria.pdf). Если внутренняя информация изменится, изменение повлияет на родительское окно, и его нужно будет изменить. Вот как скрытие информации способствует модульности; он хранит данные в комплекте с тем, что ему нужно (и скрывает от тех, кто этого не делает).

Судя по комментариям, это плохой пример, потому что нарушения скрытия информации не происходит, поскольку CUSTOM_BUTTON_ID на самом деле представляет собой данные, которые содержатся и используются родительским окном, а не элементом управления. Рисование элемента управления все еще выполняется внутри элемента управления; родительское окно просто вызывает метод Draw элемента управления.

-1

По вопросам рекламы [email protected]