Передача параметра вниз по иерархии классов
От: Ignoramus  
Дата: 29.09.05 08:05
Оценка:
Может быть кто-то уже сталкивался с такой проблемой, подскажите красивое решение.


Есть класс А, у которого есть вложенный класс, у которого есть еще вложенный класс и т.д. до класса В. Наследование не используется, только аггрегация.

И вот выясняется, что "потомку" n-го колена В понадобился один из параметров прародителя А. (Этот параметр неизменный в течение всей жизни всех объектов.)


Как ему его получить?


1) Передавать вниз по дереву в процессе создания вложенных объектов
2) То же что 1, только в обратную сторону — запрашивать параметр у родителя по цепочке вверх
3) Объявить параметр как глобальные данные

В случаях 1) и 2) нарушается инкапсуляция.

В 1) все классы выше В по иерархии должны знать, что существует какой-то там дальний потомок В и ему понадобится этот параметр и будут передавать его вниз, никак по-другому не используя. Кроме того, завтра я могу сделать другой класс В, которому параметр уже не будет нужен (или не дай бог нужен еще один параметр ), что в таком случае — всю иерархию переделывать?

В 2) наоборот, класс В должен знать что у его непосредственного предка есть еще предок, у которого тоже есть предок и т.д. до А, у которого есть необходимый параметр. В принципе, потомки должны знать своих предков , но если в цепочку предков добавится промежуточное звено, то всех потомков вроде В нужно будет об этом уведомить (переделать). Кроме того, не очень хочется открывать ВЕСЬ интерфейс предка какому-то там потомку только из-за одного параметра.

Вариант 3) не подходит, так как экземпляров А может быть несколько. Даже если бы он был один, все равно не особо красивое решение.


Вот сижу и думаю, мож какой-то паттерн на этот случай есть?
Re: Передача параметра вниз по иерархии классов
От: Vadim S. Беларусь  
Дата: 29.09.05 09:29
Оценка:
Здравствуйте, Ignoramus, Вы писали:

I>Есть класс А, у которого есть вложенный класс, у которого есть еще вложенный класс и т.д. до класса В. Наследование не используется, только аггрегация.

I>И вот выясняется, что "потомку" n-го колена В понадобился один из параметров прародителя А. (Этот параметр неизменный в течение всей жизни всех объектов.)
I>Как ему его получить?

Сдаётся мне, что ошибка в иерархии. Если B имеет какие-то отношения с A, то видимо они расположены неверно в вашей агрегатной цепочке. Так что, я бы стал думать не над способами передачи, а над способами реорганизации структуры.
Re[2]: Передача параметра вниз по иерархии классов
От: Козьма Прутков Россия  
Дата: 29.09.05 10:34
Оценка:
VS>Сдаётся мне, что ошибка в иерархии. Если B имеет какие-то отношения с A, то видимо они расположены неверно в вашей агрегатной цепочке. Так что, я бы стал думать не над способами передачи, а над способами реорганизации структуры.
Пожалуй, соглашусь: что-то тут не так. А слобо ли автору привести описание задачки? Поди, на более конкретном примере было бы яснее.
Да хранит вас господь в сухом прохладном месте...
Re[2]: Передача параметра вниз по иерархии классов
От: Ignoramus  
Дата: 29.09.05 10:56
Оценка:
Здравствуйте, Vadim S., Вы писали:

VS>Здравствуйте, Ignoramus, Вы писали:


I>>Есть класс А, у которого есть вложенный класс, у которого есть еще вложенный класс и т.д. до класса В. Наследование не используется, только аггрегация.

I>>И вот выясняется, что "потомку" n-го колена В понадобился один из параметров прародителя А. (Этот параметр неизменный в течение всей жизни всех объектов.)
I>>Как ему его получить?

VS>Сдаётся мне, что ошибка в иерархии. Если B имеет какие-то отношения с A, то видимо они расположены неверно в вашей агрегатной цепочке. Так что, я бы стал думать не над способами передачи, а над способами реорганизации структуры.


Конкретизирую задачу.

Класс А это контрол. Он состоит из нескольких элементов, каждый из которых реализован в виде класса. Каждый из элементов составной, т.е. состоит из подэлементов. Все элементы и подэлементы могут заменяться другими (смена скина, паттерн бридж). Один из подэлементов — текстовое поле, которому для измерения необходимой высоты области по событию изменение ширины требуется hwnd контрола, в виду особенности измеряющей WINAPI ф-ции.

Имхо очень удачная структура не вижу как можно еще ее реорганизовать... Есть соображения?
Re[3]: Передача параметра вниз по иерархии классов
От: Козьма Прутков Россия  
Дата: 29.09.05 11:57
Оценка:
I>Класс А это контрол. Он состоит из нескольких элементов, каждый из которых реализован в виде класса. Каждый из элементов составной, т.е. состоит из подэлементов. Все элементы и подэлементы могут заменяться другими (смена скина, паттерн бридж). Один из подэлементов — текстовое поле, которому для измерения необходимой высоты области по событию изменение ширины требуется hwnd контрола, в виду особенности измеряющей WINAPI ф-ции.

То есть контрол владеет другими контролами, среди которых в этой цепочке владения текстовое поле? Или кто такие эти подэлементы?
Да хранит вас господь в сухом прохладном месте...
Re[4]: Передача параметра вниз по иерархии классов
От: Ignoramus  
Дата: 29.09.05 12:42
Оценка:
Здравствуйте, Козьма Прутков, Вы писали:

I>>Класс А это контрол. Он состоит из нескольких элементов, каждый из которых реализован в виде класса. Каждый из элементов составной, т.е. состоит из подэлементов. Все элементы и подэлементы могут заменяться другими (смена скина, паттерн бридж). Один из подэлементов — текстовое поле, которому для измерения необходимой высоты области по событию изменение ширины требуется hwnd контрола, в виду особенности измеряющей WINAPI ф-ции.


КП>То есть контрол владеет другими контролами, среди которых в этой цепочке владения текстовое поле? Или кто такие эти подэлементы?


Да, примерно так. Контрол — владеет другими "контролами", например в окне есть несколько айтемов, каждый из которых состоит из иконки и текстового поля.

Однако HWND на них всех только один — контейнерский. Все остальные — просто объекты (поэтому я назвал суб-"контролы" в кавычках)
Re[5]: Передача параметра вниз по иерархии классов
От: Козьма Прутков Россия  
Дата: 29.09.05 13:12
Оценка:
I>Да, примерно так. Контрол — владеет другими "контролами", например в окне есть несколько айтемов, каждый из которых состоит из иконки и текстового поля.
I>Однако HWND на них всех только один — контейнерский. Все остальные — просто объекты (поэтому я назвал суб-"контролы" в кавычках)
Посмотри на модели элементов управления во всяких библиотеках, например, в WinForms. Как там сделано? Контрол имеет родителя, те, кто не имеет, на форме не рисуются (о них никто не знает). Вот и все.
Конрол имеет родителя, хочешь ты того или нет: он контрол и принадлежит либо другому контролу либо форме.
Кстати, кто у тебя создает подчиненные контролы? Их непосредственные контейнеры? Нет возможности высунуть свойство, типа, Parent (или Container) и туда совать правильный объект-контейнер?
Да хранит вас господь в сухом прохладном месте...
Re[6]: Передача параметра вниз по иерархии классов
От: Ignoramus  
Дата: 29.09.05 13:25
Оценка:
Здравствуйте, Козьма Прутков, Вы писали:

I>>Да, примерно так. Контрол — владеет другими "контролами", например в окне есть несколько айтемов, каждый из которых состоит из иконки и текстового поля.

I>>Однако HWND на них всех только один — контейнерский. Все остальные — просто объекты (поэтому я назвал суб-"контролы" в кавычках)
КП>Посмотри на модели элементов управления во всяких библиотеках, например, в WinForms. Как там сделано? Контрол имеет родителя, те, кто не имеет, на форме не рисуются (о них никто не знает). Вот и все.

КП>Конрол имеет родителя, хочешь ты того или нет: он контрол и принадлежит либо другому контролу либо форме.


Контрол-то имеет родителя, но сам ребенок об этом не знает. Знает только родитель, т.е. знание только в одну сторону, и не хотелось бы делать знание двусторонним без необходимости.

КП>Кстати, кто у тебя создает подчиненные контролы? Их непосредственные контейнеры? Нет возможности высунуть свойство, типа, Parent (или Container) и туда совать правильный объект-контейнер?


Подчиненные контролы создают их непосредственные контейнеры и сохраняют их внутри себя.

Мне тоже пришла эта идея — см. мой первый пост, №2, там же и ее недостатки.

А другого ничего нельзя придумать?
Re[5]: Передача параметра вниз по иерархии классов
От: Vadim S. Беларусь  
Дата: 29.09.05 13:43
Оценка:
Здравствуйте, Ignoramus, Вы писали:

I>Однако HWND на них всех только один — контейнерский. Все остальные — просто объекты (поэтому я назвал суб-"контролы" в кавычках)


Если контрол содержит другие контролы, то он уже тоже контейнер.
Если у вас есть контейнеры-псевдоконтролы, то значит они должны возвращать hwnd своего парента.
В таком случае каждый контрол сможет получить hwnd контейнера, который и есть реальный контрол.

А вообще, если уж вы пользуете bridge и хотите меньшую зависимость от реализации оконной системы, то я бы посоветовал не использовать hwnd в интерейсах. Может тогда уж лучше что-то вроде GetRect() или т.п. Потому что, может случиться так, что вы захотите, чтобы какой-нибудь псевдо-контейнер выдавал свои собственные размеры по какому-то новому алгоритму, не зависимо от hwnd его родителя.

В случае с hwnd вы неявно нарушаете инкапсуляцию, получая размеры в обход класса контейнер через внешнее API.
Re[6]: Передача параметра вниз по иерархии классов
От: Ignoramus  
Дата: 29.09.05 15:29
Оценка:
Здравствуйте, Vadim S., Вы писали:

VS>Здравствуйте, Ignoramus, Вы писали:


I>>Однако HWND на них всех только один — контейнерский. Все остальные — просто объекты (поэтому я назвал суб-"контролы" в кавычках)


VS>Если контрол содержит другие контролы, то он уже тоже контейнер.

VS>Если у вас есть контейнеры-псевдоконтролы, то значит они должны возвращать hwnd своего парента.
VS>В таком случае каждый контрол сможет получить hwnd контейнера, который и есть реальный контрол.

Контейнеры-псевдоконтролы пока что не знают ничего о своем родителе, включая его hwnd, и я хотел бы избежать этого знания.

VS>А вообще, если уж вы пользуете bridge и хотите меньшую зависимость от реализации оконной системы, то я бы посоветовал не использовать hwnd в интерейсах.


Так я и не хочу! Но не получается — для того чтобы вызвать некоторые API функции (DrawText, OpenThemeData) необходимо иметь hwnd

VS>Может тогда уж лучше что-то вроде GetRect() или т.п. Потому что, может случиться так, что вы захотите, чтобы какой-нибудь псевдо-контейнер выдавал свои собственные размеры по какому-то новому алгоритму, не зависимо от hwnd его родителя.


Я хочу померять размер текста с помощью DrawText. Это намного сложнее сделать руками чем GetRect.

VS>В случае с hwnd вы неявно нарушаете инкапсуляцию, получая размеры в обход класса контейнер через внешнее API.


Согласен. Но не знаю как обойти. Как ни крути, не получается полностью избавиться от контекста использования объекта. В данном случае это hwnd->hdc.
Re[7]: Передача параметра вниз по иерархии классов
От: Vadim S. Беларусь  
Дата: 29.09.05 21:31
Оценка: 2 (1) +1
Здравствуйте, Ignoramus, Вы писали:

I>Контейнеры-псевдоконтролы пока что не знают ничего о своем родителе, включая его hwnd, и я хотел бы избежать этого знания.


I>Согласен. Но не знаю как обойти. Как ни крути, не получается полностью избавиться от контекста использования объекта. В данном случае это hwnd->hdc.


Как вариант, завести отдельный объект сцена, которому неизвестна ваша иерархия, контролы и пр.
Этот объект будет давать интерфейс взаимодействия с конкретной реализацией отображения. В вашем случае он должен уметь подсчитывать, какое пространство нужно для написания в нем текста, прорисовка простых графических примитивов (прямоугольники, линии, текст, пр.), что-либо еще (по мере необходимости).
В Windows ему нужен будет hwnd или hdc.
При прорисовке главному объекту передается эта сцена (либо же он сам ее содержит), а уже он как контейнер передает ее всем своим потомкам, чтобы они могли спокойно себя в ней нарисовать. И далее по тексту (реальные контролы-контейнеры могут содержать подсцены, например, или еще как-то).
И все.
Таким образом, у вас будет разделена ф-циональность рисования (что позволит вам рисовать скины, и т.д.) от ф-циональности отображения.
Надеюсь, я вас правильно понял.
Re: Передача параметра вниз по иерархии классов
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 30.09.05 00:39
Оценка: 2 (1)
посмотри http://www.rsdn.ru/Forum/?mid=511197
Автор: DarkGray
Дата: 19.01.04
Re[7]: Передача параметра вниз по иерархии классов
От: Sinclair Россия https://github.com/evilguest/
Дата: 30.09.05 05:45
Оценка: +1
Здравствуйте, Ignoramus, Вы писали:

I>Контрол-то имеет родителя, но сам ребенок об этом не знает. Знает только родитель, т.е. знание только в одну сторону, и не хотелось бы делать знание двусторонним без необходимости.

А как, простите, ребенок собрался жить без этого знания? Ему для нормального функционирования нужна информация об окружающей среде. В частности, hwnd того окна, на котором он собрался отображаться. Это принципиальная часть контракта этого класса.
И ее обязаны обеспечить те, кто собрался его хостить.
... << RSDN@Home 1.1.4 stable rev. 510>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: Передача параметра вниз по иерархии классов
От: Ignoramus  
Дата: 03.10.05 12:19
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Ignoramus, Вы писали:


I>>Контрол-то имеет родителя, но сам ребенок об этом не знает. Знает только родитель, т.е. знание только в одну сторону, и не хотелось бы делать знание двусторонним без необходимости.

S>А как, простите, ребенок собрался жить без этого знания? Ему для нормального функционирования нужна информация об окружающей среде. В частности, hwnd того окна, на котором он собрался отображаться. Это принципиальная часть контракта этого класса.
S>И ее обязаны обеспечить те, кто собрался его хостить.

Идея такая, чтобы изолировать дочерний объект от знания контекста, в котором он хостится. Все данные о контексте передаются ему в соответствующей функции (например, hdc в Paint()).

(Даже более того, тут звучало мнение, и я с ним скорее согласен, что доступ к хендлам родительского объекта — нарушение инкапсуляции, т.к. позволяет делать API-вызовы в обход моей иерархии. Но это скорее неизбежное зло от использования callback механизма WinAPI, и на его преодоление уходит слишком много усилий — построение своего фреймворка.)

Однако, возникла такая ситуация, когда нужно получить данные о контексте за пределами соотв. функции. Например, чтобы измерить ширину/высоту текста ф-цией DrawText(hdc, ...DT_CALCRECT...) на событие WM_SIZE, необходимо знать hdc, которого нет. Поэтому и возник сабж.

Я склоняюсь к варианту, когда каждый родитель будет передавать каждому потомку при его создании некую сущность "менеджер настроек" который будет "отвечать на все вопросы" об окружающей среде. Хоть мне это и не очень нравится с точки зрения эстетики, но такое решение вроде бы неплохое в плане сопровождения (по крайней мере пока не обнаружил проблем), например, без проблем можно добавить новый параметр окружения.
Re[8]: Передача параметра вниз по иерархии классов
От: Ignoramus  
Дата: 03.10.05 12:29
Оценка:
Здравствуйте, Vadim S., Вы писали:

VS>Здравствуйте, Ignoramus, Вы писали:


I>>Контейнеры-псевдоконтролы пока что не знают ничего о своем родителе, включая его hwnd, и я хотел бы избежать этого знания.


I>>Согласен. Но не знаю как обойти. Как ни крути, не получается полностью избавиться от контекста использования объекта. В данном случае это hwnd->hdc.


VS>Как вариант, завести отдельный объект сцена, которому неизвестна ваша иерархия, контролы и пр.

VS>Этот объект будет давать интерфейс взаимодействия с конкретной реализацией отображения. В вашем случае он должен уметь подсчитывать, какое пространство нужно для написания в нем текста, прорисовка простых графических примитивов (прямоугольники, линии, текст, пр.), что-либо еще (по мере необходимости).
VS>В Windows ему нужен будет hwnd или hdc.
VS>При прорисовке главному объекту передается эта сцена (либо же он сам ее содержит), а уже он как контейнер передает ее всем своим потомкам, чтобы они могли спокойно себя в ней нарисовать. И далее по тексту (реальные контролы-контейнеры могут содержать подсцены, например, или еще как-то).
VS>И все.
VS>Таким образом, у вас будет разделена ф-циональность рисования (что позволит вам рисовать скины, и т.д.) от ф-циональности отображения.
VS>Надеюсь, я вас правильно понял.

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

В противном случае необходимо каждую API ф-цию которую будет вызывать хотя бы один класс иерархии, реализовывать в виде метода сцены, скрывая таким образом hwnd hdc и т.п. В конечном итоге это приведет к подобию собственного "фреймворка" — велосипедной надстройки над WinAPI.

Объект "сцена" будет передаваться как параметр в конструктор каждому классу иерархии, как объект "знающий ответы на все вопросы".
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.