![]() |
Модераторы: Daevaorn |
![]() ![]() ![]() |
|
W4FhLF |
|
|||
![]() found myself ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2831 Регистрация: 2.12.2006 Репутация: 20 Всего: 121 |
Приветствую всех.
Задумался над таким, интересным на мой взгляд, вопросом. Хотел бы услышать как его решают другие, наверняка есть какие-то более удобные и правильные универсальные схемы о которых я не знаю. Предположим есть набор классов, который отвечает за реализацию функционала ядра некоторой системы. Все эти классы так или иначе сходятся к одному суперклассу, точнее этот суперкласс их агрегирует, либо является связь является композиционной. В общем на диаграмме это может выглядеть так: ![]() У приложения есть GUI. Чтобы скрыть детали реализации между GUI и внутренней структурой существует некоторый промежуточный слой. Т.е. общая диаграмма выглядит так: ![]() Теперь собственно вопрос. Мне понадобилось отобразить данные "data" из класса "e" в окне подсистемы "GUI". Как лучше получить к ним доступ? Точнее вопрос даже стоит так: как определить ассоциативные связи IAbstract с остальными классами? Тут есть два пути(по-крайней мере я придумал только два): 1. Первый - это дать доступ IAbstract ко всем классам напрямую. Это будет выглядеть примерно так: ![]() 2. IAbstract имеет доступ только к методам SuperClass, а последний через серию переходников получает доступ ко всем данным. Т.е. вот так: ![]() Что, на ваш взгляд, лучше? Есть ли другие варианты? Это сообщение отредактировал(а) W4FhLF - 13.7.2008, 14:15 -------------------- "Бог умер" © Ницше "Ницше умер" © Бог |
|||
|
||||
Mal Hack |
|
|||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: 2 Всего: 261 |
Я, конечно, не большой гуру в сях и не так много сделал, но, что на сях, что на ПХП всегда делал так.
Есть гуй, который в зависимости от тех или иных ситуаций вызывает функции модуля, реализующего непосредственно решение задачи. В Qt это у меня вроде бы неплохо получилось разнести, грубо говоря: Class FormImpl {}; -> namespace modul {}; Модуль же уже обращается к еще как бы более низкому уровню аля интерфейи для работы с портами. В принципе в ряде случаев, гуй сам обращается к портам минуя модуль, например при подключении... К примеру класс обработки исключений находится на той же ступеньки иерархии, что и модуль. Грубо говоря схема состоит из трех уровней: гуй, модуль, вспомогательные части модуля, которые могут использоваться и гуем, если уж так надо. |
|||
|
||||
W4FhLF |
|
|||
![]() found myself ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2831 Регистрация: 2.12.2006 Репутация: 20 Всего: 121 |
Mal Hack, т.е. в общем случае ты описал способ №1? Этот способ кажется довольно неплохим. Если меняется любой из нижележащих классов, GUI об этом ничего не узнает, т.к. детали реализации скрывает IAbstract, но в тоже время насколько верно давать доступ IAbstract ко всем данным? Хотя, с другой стороны, способ номер №2 ничего не лучше, ибо чтобы получить некоторые данные из класса "e" класс IAbstract в любом случае должен знать их тип и уметь работать с ними. К тому же в способе №2 добавляется множество переходников во все классы, т.е. такие конструкции:
тоже не очень радуют ![]() В общем нужен разумный компромис, а может и совсем иное решение. -------------------- "Бог умер" © Ницше "Ницше умер" © Бог |
|||
|
||||
Torsten |
|
|||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 174 Регистрация: 10.6.2008 Где: Pskov Репутация: 3 Всего: 7 |
W4FhLF,
Одно из ООП гласит - не делайте божественных классов, которые умеют все и вся. Каждый класс, метод должен решать только одну задачу. Еще одно правило - всегда если возможно ослобляйте связи. В 1-ом случае у тебя их больше, чем во 2-ом, поэтому он хуже. И конечно нужно идти от того, что за задачи выполняет интерфейс - можно ли его разделить на несколько независимых интерфейсов ? У меня ни разу не было такого, чтобы интефрейс обьединял так много классов - 2, ну 3 максимум, но такое количество как у тебя на рисунках ни разу. Еще тогда нужно упоминуть о том, что нет универсальных способов для такой задачи. Все зависит от реальной ситуации, этим и сложно программирование, тут нет явных шаблонов проектирования, есть только рекомендации. А почему нельзя сделать метод у SuperClass который будет возращать get_data ? Это сообщение отредактировал(а) Torsten - 13.7.2008, 14:50 --------------------
We have no begining, we have no end. We are infinite. |
|||
|
||||
Mal Hack |
|
||||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: 2 Всего: 261 |
Да, 1 способ.
Дело даже не в этом, а в оптимальности. Ну это что-то вроде:
Смысл устанавливать лишние программные связи - никакого. Плюс, первый подход обеспечивает некую гибкость приложения. |
||||
|
|||||
W4FhLF |
|
||||||
![]() found myself ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2831 Регистрация: 2.12.2006 Репутация: 20 Всего: 121 |
С этой точки зрения хуже, да. Но вот, как уже Mal Hack упомянул, по части оптимизации как раз лучше. Если эти данные будут запрашиваться постоянно, то каждый раз придётся проходить цепочку вызовов от IAbstract до класса "e" в полном объёме, т.е. через все классы. Считаешь, это оптимально? Даже с т.з. зрения архитектуры, не говоря уже о реализации.
Классов будет порядка 5-6 и делить их как раз не хочется, т.к. по логике они являются одним целым и в самом общем случае выполняют одну задачу.
Ну вот опять же мы увеличиваем кол-во связей. Поидее, классу SuperClass вообще пофиг до внутренней структуры класса "e" в котором хранятся нужные данные. Эти данные нужны только класу-владельцу и GUI для отображения. -------------------- "Бог умер" © Ницше "Ницше умер" © Бог |
||||||
|
|||||||
Ulysses4j |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 304 Регистрация: 6.6.2007 Где: Ростов-на-Дону Репутация: 4 Всего: 10 |
Геттеры скорее всего будут встраиваться и никакого ущерба для быстродействия не будет, а если и будет, то вы все равно занимаетесь преждевременной оптимизацей (Саттер, Александреску, “Стандарты кодирования на C++”, одно из первых правил). А вот на уровне архитектуры такая цепочка это плохо, нарушает закон Деметры (“Only talk to your immediate friends”). Хотя в реальной жизни используется часто ;) -------------------- Communication is critical to the job of a programmer. C. Jazdzewski. Fatherly Advice To New Programmers |
|||
|
||||
W4FhLF |
|
|||
![]() found myself ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2831 Регистрация: 2.12.2006 Репутация: 20 Всего: 121 |
Ulysses4j, за ссылки спасибо. Но я всё-таки не понял, вы за какой подход?
![]() -------------------- "Бог умер" © Ницше "Ницше умер" © Бог |
|||
|
||||
Ulysses4j |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 304 Регистрация: 6.6.2007 Где: Ростов-на-Дону Репутация: 4 Всего: 10 |
Я не знаю, это слишком общая постановка вопроса, но то, о чем вы говорите, похоже на Façade pattern. Соответственно, второй подход.
-------------------- Communication is critical to the job of a programmer. C. Jazdzewski. Fatherly Advice To New Programmers |
|||
|
||||
The_Thing |
|
|||
Новичок Профиль Группа: Участник Сообщений: 6 Регистрация: 24.9.2007 Репутация: 1 Всего: 1 |
Что бы таких ситуаций не было делается это так:
Делай интерфейс на каждый из классов, не только на "супер класс", но и на A, B, C, D, e, f, g (IA, IB, IC, ID, Ie, If, Ig соответственно). После этого, реализуй следующую связь "IСупер класс" предоставляет доступ к интерфейсу IA, IB, IC, ID, пусть даже если они не предоставляют никаких данных (вся реализация скрыта, пока скрыта! ), если тебе понадобится открыть данные ты всегда сможешь добавить в интерфейс нужные данные. Интерфейс IA, IB должен предоставлять доступ к интерфейсу к Ie и If, а IC и ID к Ig. Доступ к Ie осуществляется таким образом: Получаешь интерфейс ISuperClass, от него интерфейс IA, от него Ie у него get_data. Таким образом каждый класс отвечает за свою задачу, и если тебе прийдется что-то поменять, ты не затрагиваешь всю структуру приложения.. так как каждый работает только с наследуемым. Я делаю так, очень удобно, проблем не возникает. |
|||
|
||||
mes |
|
|||
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 144 Всего: 250 |
3й вариант: совместить оба подхода: 1. определить структуры данных 2. раделить ядро на компоненты каждый компонент состоит из одного или множества объектов контролирующих данные к внутренним объектам нет доступа извне компонент предоставляет доступ к любым данным своих объектов 3. Разделить Гуи на компоненты несколько виджетов реализующих общую смысловую функциональность представлены одним компонентом (точнее делегируют функции одного компонента) 4. реализовать логику взаимодействия между гуи- и ядро- компонентами |
|||
|
||||
Lazin |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 41 Всего: 154 |
это вызовет рост количества кода, при добавлении нового класса, тебе потребуется добавить еще и интерфейс для его, да и вообще я тут не вижу решения... Эту проблему можно решить используя принцип инверсии зависимости (IoC) Допустим у нас есть некоторый объект, который что-то реализует, и имеет набор свойств и функций - сервис. В общем случае нужно ввести дополнительную сущность(объект посредник), через которую клиент(GUI) сможет влиять на объект сервис... Например в интерфейс базового класса можно добавить вирт. функцию, которая бы возвращала такой proxy(посредник) объект. В качестве посредника, может выступать, к примеру xml документ, содержащий описание состояния (точнее той его части, которую может изменять клиент) и мета-информацию (типы переменных, различные описания), получив proxy объект, клиент может создать форму с виджетами для его редактирования динамически, когда пользователь изменит свойство, клиент(GUI класс) может отправить измененный xml документ( а еще лучше - его изменившуюся часть) сервису, который обработает его и изменит свое состояние... то-есть, в итоге, произойдет вызов метода, но не напрямую. Конечно xml это не очень эффективно, но его я привел только в качестве примера (который может вполне может быть использован). Можно придумать какую угодно реализацию proxy объекта, который, в общем случае должен содержать мета-информацию (описывать тип каждого свойства, название для пользователя и т.д.) и состояние (значение свойства). Можно придумать, к примеру структуру содержащую список указателей на методы объекта...
|
||||
|
|||||
Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 41 Всего: 154 |
Написал пример того, что я имел ввиду, только вместо создания диалога, класс Client использует для ввода значений консоль...
|
|||
|
||||
W4FhLF |
|
|||
![]() found myself ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2831 Регистрация: 2.12.2006 Репутация: 20 Всего: 121 |
mes, мне кажется ты представил разновидность варианта №1. В данном случае IAbstract - компонент для всех составных объектов классов SuperClass, A,B,C,D... Единственное, если базовых классов будет несколько, каждый из которых решает свою собственную задачу, то и IAbstract должно быть несколько, каждый из которых реализует интерфейс взаимодействия с внутренними данными составных классов.
Lazin, ты взорвал мой мозг ![]() -------------------- "Бог умер" © Ницше "Ницше умер" © Бог |
|||
|
||||
Partizan |
|
|||
![]() Let's do some .NET ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 2828 Регистрация: 19.12.2005 Где: Санкт-Петербург Репутация: 4 Всего: 67 |
W4FhLF, задача слишком абстрактна для того чтобы выбирать какой из вариантов лучше. Тем не менее я склоняюсь ко 2 варианту...
А такие конструкцуии явно указывают на ошибки с проектировании...
В общем надо плясать от конкретной задачи и уже там решать что лучше. -------------------- СУВ, Partizan. |
|||
|
||||
![]() ![]() ![]() |
Правила форума "С++:Общие вопросы" | |
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |