привет.
есть некий интерфейс IElement. В иерархии есть класс IGroup, который имеет все свойства интерфейса IElement, но отличается лишь тем, что может внутри хранить другие элементы и группы (некое дерево).
вопрос в том, какой паттерн используется для работы с такой иерархией?
Как это описать так, чтобы с одной стороны я всегда знал, какой тип у m_children[i], и с другой стороны мог работать с группой, как с элементом?
Пока в голову пришел только Посетитель (GoF): создать итератор на основе посетителя всей иерархии.
есть какие-то стандартные приемы, примеры?
Здравствуйте, sax0n, Вы писали:
S>есть какие-то стандартные приемы, примеры?
Обычно в таких случаях элемент сразу делается группой, т.е. не создают два класса — Элемент и Группа, а используют один. В качестве примера могу сослаться на объект Окно в Win32 API. Оно имеет указатель на родителя, входит в список сиблингов и хранит указатель на список чайлдов.
Другой вариант — сделать, как сделали Вы. Тогда смотрите в сторону паттерна Компоновщик.
P.S.: А для чего Вам нужна иерархия элементов? За выполнение каких обязанностей будет отвечать класс Элемент?
Здравствуйте, Кирилл Лебедев, Вы писали:
КЛ>Обычно в таких случаях элемент сразу делается группой, т.е. не создают два класса — Элемент и Группа, а используют один. В качестве примера могу сослаться на объект Окно в Win32 API. Оно имеет указатель на родителя, входит в список сиблингов и хранит указатель на список чайлдов.
скиньте, пожалуйста, пример. для ГУИ тоже очень интересно посмотреть пример.
кстати, в примере из вики по ссылке ниж, по сути, элемент и есть группа (по интерфейсу).
КЛ>Другой вариант — сделать, как сделали Вы. Тогда смотрите в сторону паттерна Компоновщик.
В том примере компоновщик делает проверку во время выполнения. такое и я могу сделать. а я хочу во время компиляции, а лучше вообще без доступа к группирующим методам
КЛ>P.S.: А для чего Вам нужна иерархия элементов? За выполнение каких обязанностей будет отвечать класс Элемент?
В целом, у меня есть набор элементов (IElement) в пределах определенной области.
В этой области я могу создавать свои объекты (IObject), свойства которых могут быть основаны на свойствах 1+ IElement.
в иерархии IObject есть такие, которые могут хранить в себе другие IObject (IGroup).
В итоге у меня есть дерево IObject, по которому я могу пройтись, но я так же хочу иметь возможность сохранить информацию о типе, т.е. знать, что конкретный IObject есть IGroup или его наследник.
Возможно, я в корне неправильно составил иерархию.
Примером аналогии могут быть теги из HTML, например, <div> — сам по себе это ITag, но у него есть children()
вот что-то типа такого нужно сделать.
Здравствуйте, sax0n, Вы писали:
S>Как это описать так, чтобы с одной стороны я всегда знал, какой тип у m_children[i], и с другой стороны мог работать с группой, как с элементом? S>Пока в голову пришел только Посетитель (GoF): создать итератор на основе посетителя всей иерархии. S>есть какие-то стандартные приемы, примеры?
Здравствуйте, Ikemefula, Вы писали:
I>"итератор на основе посетителя" — это сильно
это не самое худшее, что приходило в голову
нужно еще разок GoF перечитать.. как-то не собирается воедино все.
Здравствуйте, sax0n, Вы писали:
I>>"итератор на основе посетителя" — это сильно S>это не самое худшее, что приходило в голову S>нужно еще разок GoF перечитать.. как-то не собирается воедино все.
Для паттернов, возьми книгу например Джошуа Кериевски, "Рефакторинг с использованием шаблонов".
В ней паттерны расписываются гораздо лучше и понятнее, автор злоупотребил Фаулером, но в целом очень, очень сильно.
Кроме того, есть книга Кента Бека "Экстремальное программирование. Разработка через тестирование" — просто адская вещь.
GoF это вобщем то словарь, что бы можно было читать книги вроде перечисленых. Без них она смысла в ней мало.
Здравствуйте, Ikemefula, Вы писали:
I>Кроме того, есть книга Кента Бека "Экстремальное программирование. Разработка через тестирование" — просто адская вещь.
Это не та книжка, в которой Кент Бек объяснял пользу юнит-тестирования на примерчиках:
Здравствуйте, sax0n, Вы писали:
S>скиньте, пожалуйста, пример. для ГУИ тоже очень интересно посмотреть пример.
Посмотрите здесь.
S>В том примере компоновщик делает проверку во время выполнения. такое и я могу сделать. а я хочу во время компиляции, а лучше вообще без доступа к группирующим методам
Зачем?
S>Возможно, я в корне неправильно составил иерархию.
ИМХО, слишком сложно. Да и непонятно, зачем нужны разные типы. Создайте один объект — Узел дерева. Он может быть и листом, и поддеревом. И в любой момент преобразоваться из листа в поддерево, а из поддерева — в лист (путём добавления или удаления дочерних элементов).
Если уж такое решение кажется некрасивым, то создайте два класса — Элемента и Группа и преобразуйте один к другому в ран-тайме.
А вообще, дизайн сильно зависит от того, какие операции Вы будете выполнять над этим деревом. Пока что Вы описали его в статике, а чтобы посоветовать что-то конкретное хорошо бы знать динамику.
Здравствуйте, Кирилл Лебедев, Вы писали:
I>>Кроме того, есть книга Кента Бека "Экстремальное программирование. Разработка через тестирование" — просто адская вещь. КЛ>Это не та книжка, в которой Кент Бек объяснял пользу юнит-тестирования на примерчиках:
КЛ>
Здравствуйте, Ikemefula, Вы писали:
I>Да, она. Только там не про пользу юнит-тестирования, а про решение задачи с использованием юнит-тестирования.
В таком случае, я бы не стал рекомендовать эту книгу по двум основаниям.
Во-первых, соотношения курсов валют определяют финансовые площадки, а не непонятный класс Money.
Во-вторых, дизайн, в котором названия валют зашиты в виде функций, ни к чему хорошему не приведёт: код придётся изменять при желании поддержать новую валюту.
Резюме: подход к проектированию, который не позволяет вовремя просечь эти вещи, ИМХО, не является работоспособным.
Здравствуйте, sax0n, Вы писали:
S>Книжку многие рекомендуют, так что почитать стоит. но конкретно этот вырванный из контекста код выглядит немного некрасиво ( Money.dollars )
Здравствуйте, Кирилл Лебедев, Вы писали:
КЛ>Посмотрите здесь.
WinAPI в теме про ООП — не особо хороший пример ИМХО. C-style со своими плюшками. Или я не туда посмотрел?
S>>В том примере компоновщик делает проверку во время выполнения. такое и я могу сделать. а я хочу во время компиляции, а лучше вообще без доступа к группирующим методам КЛ>Зачем?
Александреску начитался =)
а вообще, почему Зачем?! для легкости и однозначности использования, типобезопасности и т.д.
КЛ>ИМХО, слишком сложно. Да и непонятно, зачем нужны разные типы. Создайте один объект — Узел дерева. Он может быть и листом, и поддеревом. И в любой момент преобразоваться из листа в поддерево, а из поддерева — в лист (путём добавления или удаления дочерних элементов).
КЛ>Если уж такое решение кажется некрасивым, то создайте два класса — Элемента и Группа и преобразуйте один к другому в ран-тайме.
почему же сложно?
я хочу, чтобы в моем интерфейсе IElement только в нужный момент появлялись методы интерфейса IGroup, чтобы они были вообще недоступны для обычных элементов (а не были заглушки).
не хочется делать так для всех элементов:
structure< IElement >::iterator iter;
if ( iter->hasChildren() ){}
а хочется точно знать, что у этого элемента могут быть (0+ штук) или не могут быть элементы вообще и т.д. Можно сделать и так, как вы предлагаете. просто есть возможность еще поиграться и выбрать самую удобную, красивую и безопасную архитектуру.
встречный вопрос, а что тогда почитать?
у меня лежит GoF и Фаулер "Проектирование корпоративных приложений".
Хочется чего-то практического, а не просто справочник полистать по паттернам.
Здравствуйте, Кирилл Лебедев, Вы писали:
I>>Да, она. Только там не про пользу юнит-тестирования, а про решение задачи с использованием юнит-тестирования.
КЛ>В таком случае, я бы не стал рекомендовать эту книгу по двум основаниям.
КЛ>Во-первых, соотношения курсов валют определяют финансовые площадки, а не непонятный класс Money.
Если бы ты читал книгу, то там бы и прочел, что Кент Бек и говорит, что Money описывает валюту, а не курсы валют.
Курсы валют для класса Money это внешняя сущность. Задача, на которой он показывал TDD, была исключительно про валюту.
КЛ>Во-вторых, дизайн, в котором названия валют зашиты в виде функций, ни к чему хорошему не приведёт: код придётся изменять при желании поддержать новую валюту.
У меня еще одно сомнение, что ты читал книгу.
КЛ>Резюме: подход к проектированию, который не позволяет вовремя просечь эти вещи, ИМХО, не является работоспособным.
Здравствуйте, Кирилл Лебедев, Вы писали:
КЛ>Здравствуйте, sax0n, Вы писали:
S>>встречный вопрос, а что тогда почитать?
КЛ>Посмотрите здесь и здесь.
не совсем подходит. нужна 1-2 книжки, а не 100500..
Здравствуйте, Кирилл Лебедев, Вы писали:
S>>Книжку многие рекомендуют, так что почитать стоит. но конкретно этот вырванный из контекста код выглядит немного некрасиво ( Money.dollars )
КЛ>Там везде такой код.
Здравствуйте, sax0n, Вы писали:
S>встречный вопрос, а что тогда почитать? S>у меня лежит GoF и Фаулер "Проектирование корпоративных приложений". S>Хочется чего-то практического, а не просто справочник полистать по паттернам.
Фаулер это немного другая область.
Попробуй те книги что я тебе предложил.
Если уж сильно не доверяешь Кенту Беку, посмотри книгу Физерса "Legacy Code" или Роберта Мартина "Чистый код", но это достаточно сложные книги.
Одно плохо — у Фаулер, Физерс, Мартин, Бек, Кериевски, Эванс, Канингем — это одна и таже банда.
Они все дизайн выводят через тестирование/рефакторинг/итерации.
Если ты хочешь посмотреть деяния другой ОПГ — попробуй Буча или Лармана, там совершенно другой подход к проектированию. Но лично я плохо знаком с работами этих товарищей.
Кстати, есть такая вещь, как Funq, автор — Daniel Cazzulino записал серию скринкастов как он разрабатывал этот фреймворк.
Там используется именно тот подход, который описывает Кент Бек в книге про TDD.