Который раз натыкаюсь на такую ситуевину:
* есть некий объект test_object
* есть контейнер с такими объектами — test_container
* обо всех изменениях test_container и хранящихся в нем test_object надо предупредить некий внешний класс (observer).
* кого предупреждать, знает test_container (хранит ссылку/указатель на observer)
внимание, вопрос: как это изящно реализовать?
точнее, можно ли сделать что-то изящнее, чем в каждом test_object хранить ссылку/указатель на test_container или observer?
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Который раз натыкаюсь на такую ситуевину: ЗХ>* есть некий объект test_object ЗХ>* есть контейнер с такими объектами — test_container ЗХ>* обо всех изменениях test_container и хранящихся в нем test_object надо предупредить некий внешний класс (observer). ЗХ>* кого предупреждать, знает test_container (хранит ссылку/указатель на observer)
ЗХ>внимание, вопрос: как это изящно реализовать? ЗХ>точнее, можно ли сделать что-то изящнее, чем в каждом test_object хранить ссылку/указатель на test_container или observer?
ЗХ>ЗЫ: Язык — С++.
И при этом ни тот ни другой не может быть сингтоном?
Здравствуйте, GlebZ, Вы писали:
ЗХ>>Который раз натыкаюсь на такую ситуевину: ЗХ>>* есть некий объект test_object ЗХ>>* есть контейнер с такими объектами — test_container ЗХ>>* обо всех изменениях test_container и хранящихся в нем test_object надо предупредить некий внешний класс (observer). ЗХ>>* кого предупреждать, знает test_container (хранит ссылку/указатель на observer)
ЗХ>>внимание, вопрос: как это изящно реализовать? ЗХ>>точнее, можно ли сделать что-то изящнее, чем в каждом test_object хранить ссылку/указатель на test_container или observer?
ЗХ>>ЗЫ: Язык — С++. GZ>И при этом ни тот ни другой не может быть сингтоном?
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Здравствуйте, GlebZ, Вы писали:
ЗХ>>>Который раз натыкаюсь на такую ситуевину: ЗХ>>>* есть некий объект test_object ЗХ>>>* есть контейнер с такими объектами — test_container ЗХ>>>* обо всех изменениях test_container и хранящихся в нем test_object надо предупредить некий внешний класс (observer). ЗХ>>>* кого предупреждать, знает test_container (хранит ссылку/указатель на observer)
ЗХ>>>внимание, вопрос: как это изящно реализовать? ЗХ>>>точнее, можно ли сделать что-то изящнее, чем в каждом test_object хранить ссылку/указатель на test_container или observer?
ЗХ>>>ЗЫ: Язык — С++. GZ>>И при этом ни тот ни другой не может быть сингтоном?
ЗХ>Хиииитренький! Неа, не может.
Ну так сделай подобный singleton, обзови его, например, EventManager — и регистрируй на нем получателей сообщений. Изящней, или нет я не скажу, но я так делал (правда по другим причинам). Вариант, когда объекты связаны в дерево и по этому дереву можно было бегать, мне всегда больше нравился.
С уважением, Gleb.
PS: кажется на сайте Фаулера я видел подобные паттерны — здесь. Ессно с некоторым уклоном в Java и C#.
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Который раз натыкаюсь на такую ситуевину: ЗХ>* есть некий объект test_object ЗХ>* есть контейнер с такими объектами — test_container ЗХ>* обо всех изменениях test_container и хранящихся в нем test_object надо предупредить некий внешний класс (observer). ЗХ>* кого предупреждать, знает test_container (хранит ссылку/указатель на observer)
ЗХ>внимание, вопрос: как это изящно реализовать? ЗХ>точнее, можно ли сделать что-то изящнее, чем в каждом test_object хранить ссылку/указатель на test_container или observer?
ЗХ>ЗЫ: Язык — С++.
Поскольку test_object создается из кода test_container (или по крайней мере в нем регистрируется), то вполне логично сделать события в test_object, которые будут отлавливаться в test_container.
Здравствуйте, Other Sam, Вы писали:
ЗХ>>Который раз натыкаюсь на такую ситуевину: ЗХ>>* есть некий объект test_object ЗХ>>* есть контейнер с такими объектами — test_container ЗХ>>* обо всех изменениях test_container и хранящихся в нем test_object надо предупредить некий внешний класс (observer). ЗХ>>* кого предупреждать, знает test_container (хранит ссылку/указатель на observer)
ЗХ>>внимание, вопрос: как это изящно реализовать? ЗХ>>точнее, можно ли сделать что-то изящнее, чем в каждом test_object хранить ссылку/указатель на test_container или observer?
ЗХ>>ЗЫ: Язык — С++.
OS>Поскольку test_object создается из кода test_container (или по крайней мере в нем регистрируется), то вполне логично сделать события в test_object, которые будут отлавливаться в test_container.
+1. В конце концов, на этом и остановился.
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Который раз натыкаюсь на такую ситуевину: ЗХ>* есть некий объект test_object ЗХ>* есть контейнер с такими объектами — test_container ЗХ>* обо всех изменениях test_container и хранящихся в нем test_object надо предупредить некий внешний класс (observer). ЗХ>* кого предупреждать, знает test_container (хранит ссылку/указатель на observer)
ЗХ>внимание, вопрос: как это изящно реализовать?
Аспекты?
ЗХ>ЗЫ: Язык — С++.
Правда не знаю, есть ли реализация для С++. Но что-то подсказывет что должна быть.
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Который раз натыкаюсь на такую ситуевину: ЗХ>* есть некий объект test_object ЗХ>* есть контейнер с такими объектами — test_container ЗХ>* обо всех изменениях test_container и хранящихся в нем test_object надо предупредить некий внешний класс (observer). ЗХ>* кого предупреждать, знает test_container (хранит ссылку/указатель на observer)
ЗХ>внимание, вопрос: как это изящно реализовать? ЗХ>точнее, можно ли сделать что-то изящнее, чем в каждом test_object хранить ссылку/указатель на test_container или observer?
ЗХ>ЗЫ: Язык — С++.
С моей точки зрения хранить указатели на test_container уже довольно изящно
Чтобы было красивше, обзовите test_container observer'ом и при создании test_object'ов регистрируйте test_container'а слушать их события.
Если на самом деле события всегда интересны одному и только одному внегнему объекту, то можно сразу его регистрировать обсёрвером test_object'ов. Тогда test_container будет отвечать только за создание/уничтожение
Зверёк Харьковский пишет:
> Который раз натыкаюсь на такую ситуевину: > * есть некий объект test_object > * есть контейнер с такими объектами — test_container > * обо всех изменениях test_container и хранящихся в нем test_object > надо предупредить некий внешний класс (observer). > * кого предупреждать, знает test_container (хранит ссылку/указатель на > observer) > > внимание, вопрос: как это изящно реализовать? > точнее, можно ли сделать что-то изящнее, чем в каждом test_object > хранить ссылку/указатель на test_container или observer? > > ЗЫ: Язык — С++.
Мне кажется, что сдесь хорошо подойдет механизм сигналов и слотов,
у test_object есть сигналы, которые перехватывает test_container, в
test_container тоже можно определить сигналы.
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>внимание, вопрос: как это изящно реализовать?
А Вы хотите это сделать для того, чтобы уменьшить количество памяти, необходимой для test_object? Или для красоты дизайна?
Если для уменьшения памяти, то есть одно прикольное решение...
Здравствуйте, stalcer, Вы писали:
ЗХ>>внимание, вопрос: как это изящно реализовать?
S>А Вы хотите это сделать для того, чтобы уменьшить количество памяти, необходимой для test_object? Или для красоты дизайна?
И то, и другое.
S>Если для уменьшения памяти, то есть одно прикольное решение...
Я весь внимание.
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>И то, и другое.
И то и другое в данном сллучае не получится .
ЗХ>Я весь внимание.
Это решение скорее подходит для экстремальных ситуаций, когда любой ценой необходимо уменьшить количество памяти, причем количество объектов в контейнере достаточно велико. Т.е. избавиться в test_object от указателя на parent контейнер или на сам обсервер.
Делается специальный контейнер, в котором объекты лежат на страницах памяти. Адрес начала страницы — кратный ее размеру (т.е. aligned). Размер, желательно — степень двойки.
В начале каждой страницы — заголовок где и хранится дополнительная информация, например, указатель на сам контейнер.
Дык вот. При таком хранении имея указатель на объект, т.е. 'this' всегда можно (с помощью битового наложения константной маски) найти адрес начала страницы, и получить необходимую информацию из ее заголовка.
Здравствуйте, stalcer, Вы писали:
S>Это решение скорее подходит для экстремальных ситуаций, когда любой ценой необходимо уменьшить количество памяти, причем количество объектов в контейнере достаточно велико. Т.е. избавиться в test_object от указателя на parent контейнер или на сам обсервер.
S>Делается специальный контейнер, в котором объекты лежат на страницах памяти. Адрес начала страницы — кратный ее размеру (т.е. aligned). Размер, желательно — степень двойки. S>В начале каждой страницы — заголовок где и хранится дополнительная информация, например, указатель на сам контейнер. S>Дык вот. При таком хранении имея указатель на объект, т.е. 'this' всегда можно (с помощью битового наложения константной маски) найти адрес начала страницы, и получить необходимую информацию из ее заголовка.
Ага, я делал такую штуку. Устроено все было примерно так:
1. Все контейнеры автоматически регистрировались в синглтоне — списке контейнеров.
2. У каждого контейнера был подконтрольный ему массив хранимых элементов.
3. Хранимые объекты распределялись только в этих массивах.
4. Ну там, соответственно удвоение размера массива при превышении емкости, уполовинивание при достижении 25% и прочая муть, связанная с управлением динамическими массивами...
5. Хранимые элементы реализовывали свойство Owner при помощи поиска диапазона адресов, включающего this, в синглтон-списке. Конечно, некоторая потеря производительности при этом имела место (по сравнению с наличием указателя), но поскольку список диапазонов поддерживался в отсортированном состоянии, особых проблем не возникало.
Такая система хорошо работает в тех случаях, когда хранимые элементы малы по объему, зато их очень много. Я делал это в Delphi. Размер хранимых данных был 8 байт, поэтому пользоваться VCL-коллекциями совсем не хотелось: это удвоило бы размер каждого элемента.
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Конечно, некоторая потеря производительности при этом имела место (по сравнению с наличием указателя), но поскольку список диапазонов поддерживался в отсортированном состоянии, особых проблем не возникало.
Если делать как я написал, то потери производительности не будет вообще. Одна дополнительная команда AND с константным аргументом пролетает незаметно.
Здравствуйте, stalcer, Вы писали: S>Если делать как я написал, то потери производительности не будет вообще. Одна дополнительная команда AND с константным аргументом пролетает незаметно.
Согласен. Но это потребует некоторых танцев с выделением памяти
... << RSDN@Home 1.1.4 beta 4 rev. 347>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Который раз натыкаюсь на такую ситуевину: ЗХ>* есть некий объект test_object ЗХ>* есть контейнер с такими объектами — test_container ЗХ>* обо всех изменениях test_container и хранящихся в нем test_object надо предупредить некий внешний класс (observer). ЗХ>* кого предупреждать, знает test_container (хранит ссылку/указатель на observer)
ЗХ>внимание, вопрос: как это изящно реализовать? ЗХ>точнее, можно ли сделать что-то изящнее, чем в каждом test_object хранить ссылку/указатель на test_container или observer?
ЗХ>ЗЫ: Язык — С++.
Воспользуйся паттерном AbstractFactory и в ней регистрируй test_object в std::list, а для извещения об измениях в каком-то из объектов test_object, создай метод у фабрики типа OnNotify() и вызвай его AbstractFactory::Instance()->OnNotify(); в test_object а фабрика будет по циклу проходить std::list и рассылать извещение а в извещении можешь поместить сообщение ( Message(int TypeMessage,void* ObjectMessage)) и т.д. и т.п.
Итого у тебя отпадет test_container(будет std::list в фабрике) и observer(нужно будет добавить обработчик сообщений в test_object).