|
|
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
Предположим у нас есть некий класс (C#): Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. Все 3 класса используются в программе. И тут мне потребовался класс "цветная коробка, обладающая весом". И ещё один - "цветная коробка, обладающая весом и с рисунком на каждой стороне". Как в данном случае правильно срефакторить и создать новые классы? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.03.2011, 15:08 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
а зачем здесь наследование? покажи контекст использования - тогда поразмышляем. а пока я вижу совершенно разные типы, между собой не связанные. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.03.2011, 18:01 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
Это пример. Есть класс №1 с набором свойств и методов. Есть классы №2 и №3, расширяющие класс №1. И вот возникает ситуация, что нужен класс №4, который бы включал в себя функциональность классов №1, №2, №3 и добавлял что-то своё. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.03.2011, 20:25 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
RazielЭто пример. Есть класс №1 с набором свойств и методов. Есть классы №2 и №3, расширяющие класс №1. И вот возникает ситуация, что нужен класс №4, который бы включал в себя функциональность классов №1, №2, №3 и добавлял что-то своё. Опять, ты приводишь в качестве задачи - реализацию. а придумай сначала задачу где одним из очевидных(возможных) решений являлась бы такая иерархия классов. И тогда я(и возможно другие члены форума) бы с удовольствием решил как это обойти. а пока ответ один: Не делай больше так. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 06.03.2011, 00:51 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
RazielКак в данном случае правильно срефакторить и создать новые классы? Ну, вообще-то в данном случае правильно использовать множественное наследование. Но поскольку убогие инструменты требуют как-то выкручиваться, придётся использовать не наследование. Тупой, но иногда "просто и сердито" метод - реализовать необходимый функционал в базовом классе, но открывать только в некоторых потомках. Скажем, сделать методы Get/SetWeight как protected в Box, а также сделать включающий их интерфейс Solid. Правильный в общем случае метод - сделать класс со смыслом "контейнер-носитель" и некоторое количество "плагинов" к нему. То есть "цветная коробка с весом" будет состоять из "коробки", плагина "цвет" и плагина "вес". ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 06.03.2011, 02:31 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
Множественного наследования не существует, не применяя магию в виде правки IL кода. В интернете пишут, что лучше использовать интерфейсы чтобы как-то реализовать оба класса. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.03.2011, 13:30 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
А как попроще реализовать эти плагины? Интерфейсы тут наврядли помогут. Разве что реализации выносить в отдельные классы, а в самой иерархии их просто дёргать. Как-то не очень... Вообще есть какой-нить паттерн на данную ситуацию? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.03.2011, 15:36 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
RazielИнтерфейсы тут наврядли помогут. Разве что реализации выносить в отдельные классы, а в самой иерархии их просто дёргать. Как-то не очень... В дельфе есть такая полезная директива implements. Выглядит примерно так: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. В таких случаях просто спасает. Посмотрите, может в C# есть что-нибудь подобное. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.03.2011, 20:48 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
Raziel... И тут мне потребовался класс "цветная коробка, обладающая весом". И ещё один - "цветная коробка, обладающая весом и с рисунком на каждой стороне". Как в данном случае правильно срефакторить и создать новые классы? Если потребовался - сделай сразу. Впихни все свойства и методы. Если вопрос стоит так что нужно "заложить возможность в будущем добавлять функционал" - то для этого можно надстроить много надстроек вплоть до "списков свойств". (Никто ведь не ограничивает верно?). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.03.2011, 21:00 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
softwarerRazielИнтерфейсы тут наврядли помогут. Разве что реализации выносить в отдельные классы, а в самой иерархии их просто дёргать. Как-то не очень... В дельфе есть такая полезная директива implements. Выглядит примерно так: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. В таких случаях просто спасает. Посмотрите, может в C# есть что-нибудь подобное. В языках без множественного наследования (сишарп, дельфа, ява, ди) есть интерфейсы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.03.2011, 01:04 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
SiemarglВ языках без множественного наследования (сишарп, дельфа, ява, ди) есть интерфейсы. Офигеть, какая неожиданная, ценная и актуальная информация. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.03.2011, 17:59 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
softwarerSiemarglВ языках без множественного наследования (сишарп, дельфа, ява, ди) есть интерфейсы. Офигеть, какая неожиданная, ценная и актуальная информация.... которые заменяют задачи множественного наследования ) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.03.2011, 18:03 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
Можно посмотреть на дело немного иначе. Начать не с иерархии коробок, а с интерфейсов. Тут видятся следующие 5 интерфейсов: - Трехмерное - Цветное - Весящее - Разрисованное - Ящик Эти 5 интерфейсов не связаны наследованием. Они все независимы. Трехмерным может быть не только ящик, но и шар и прочее. Цветное может быть не только трехмерным, но и плоским. И так далее. Определяя такие интерфейсы мы получаем возможность написать функции, которые обрабатывают все трехмерное лишь с учетом его трехмерности. И независимо от того, ящик это или шар. (Или любое цветное, весящее и т.д.). Увеличиваются возможности повторного использования кода. Дальше возникает вопрос уже о воплощении ящиков, как о носителях конкретной реализации различных комбинаций эти 1 обязательного + 4 опциональных интерфейсов (инт. "Ящик" плюс разные "перламутровые пуговицы"). Воплощение ящиков может быть сделано в виде некоторой иерархии. Плюс объекты-реализаторы опциональных интерфейсов, которые сами вне иерархии ящиков. Например (пардон, лень рисовать, я уж текстом): == Вне иерархии ящиков - комплект имплементаторов опциональной функциональности: [1] ПодержкаТрехмерного - держит габариты, вычисляет объем etc., и может управляться снаружи контроллером поддержки трехмерного (возможно также извещать его посланиями вроде "Трехмерность изменилась"). Может само предоставлять интерфейс Трехмерное. [2] ПоддержкаЦветного - аналогично [1], но про Цветное. Может быть управляется снаружи контроллером поддержки цветного [3] ПоддержкаВесящего - может управляться контроллером весящего [4] ПоддержкаРазрисованного - может управляться контроллером разрисованного (Этот комплект может быть применен не только к ящикам но и к шарам или иному) == Иерархия ящиков - воплощает ящики, иногда привлекая имплементаторы разной функциональности: (1) БазовыйЯщик - реализует интерфейс Ящик базовым образом (2) ЯщикТрехмерный - потомок (1). Поддерживает функционал Трехмерного через композицию. Имеет в себе экземпляр класса [1], которому подсовывает себя в качестве контроллера трехмерности. Его же выдает наружу при запросе интерфейса, или делегирует ему вызовы. (3) ЯщикЦветной - потомок (2). Поддерживает Цветное с помощью композиции, инстанциируя [2], и будучи контроллером Цветного (4) ЯщикВесящий - потомок (2). Поддерживает Весящее через [3] (5) ЯщикЦветнойВесящий - потомок (3). Поддерживает Весящее через [3]. А можно сделать и потомком (4), поддерживающим цветное через [2]. Или вовсе потомком (2), поддерживающим цветное через [2], а весящее через [3]. Выбор варианта зависит от того, насколько обширна реализация "контроллера Цветного", "контроллера Весщяего". Одно дело, когда, например, надо обрабатывать много специфичных событий от имплементатора. Много кода по реализации контроллера. А другое дело, когда имплементатор надо просто инстанциировать и выдавать/делегировать его при запросе интерфейса. Если есть разница, то выбрать тот вариант, который требует написать меньше кода в (5). Впоследствии родословную (5) можно будет менять не сильно беспокоя остальную иерархию. (6) ЯщикЦветнойВесящийРазрисованный - потомок (5), поддерживает Разрисованное через [4] ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.03.2011, 20:39 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
Mumbo[3] ПоддержкаВесящего - может управляться контроллером весящего Mumbo, это всё как бы очевидно. Проблема в том, что когда весящими должны быть 10 разных классов, делать 10 реализаций как бы тупо, а делать 10 тупых переадресаций на одну реализацию немногим умнее. Наследование классов и implements - два метода, позволяющие обойтись без копирования, поэтому именно их хочется использовать в подобных случаях. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.03.2011, 22:07 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
softwarerделать 10 реализаций как бы тупо, согласен. softwarerа делать 10 тупых переадресаций на одну реализацию немногим умнее. не согласен. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.03.2011, 23:24 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
В С++ все легко решается с помощью множественого наследования с виртуальным базовым классом, в С# хз...онли интерфейс наверно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.03.2011, 00:35 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
softwarerMumbo[3] ПоддержкаВесящего - может управляться контроллером весящего Mumbo, это всё как бы очевидно. Проблема в том, что когда весящими должны быть 10 разных классов, делать 10 реализаций как бы тупо, а делать 10 тупых переадресаций на одну реализацию немногим умнее. Наследование классов и implements - два метода, позволяющие обойтись без копирования, поэтому именно их хочется использовать в подобных случаях. softwarer, оборот "это всё как бы очевидно" - это похоже на тупое фиглярство и понты. А это все никому не нужно, так что давайте лучше разберемся. Когда используем, например, строку, в качестве переменной-члена класса, то это же привычно и нормально. Да? Никого не смущает, когда какой-нибудь getName() класса обращается к этой строке. Никто не считает это лишней переадресацией (кроме несведущих людей). Когда используем кроме переменной класса Строка еще и переменную класса Вектор, а также переменную класса Дерево, и переменные разных других классов это тоже привычно и нормально. Никто не считает это лишней реализацией (за исключением недопонимающих). Потому что каждый класс занимается своим делом. Аналогично и в рассмотренном примере. Переменные классов ПоддержкаЦветного и ПоддержкаВесящего - это аналоги переменной класса Строка, переменной класса Вектор. С тем небольшим отличием, что они могут поддерживать (если надо) еще и управление со стороны внешнего контроллера. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.03.2011, 01:23 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
Mumbosoftwarer, оборот "это всё как бы очевидно" - это похоже на тупое фиглярство и понты. А это все никому не нужно, так что давайте лучше разберемся. Давайте разберёмся. Ваш пост, если убрать воду, сводится к четырём мыслям: для описания наборов характеристик следует использовать интерфейсы, для каждого интерфейса нужна стандартная реализация, оконечные классы должны включать эту реализацию и переадресовывать ей запросы, схема наследования оконечных классов строится исходя из минимальности кодирования. Вы правда уверены, что это неожиданные и ценные находки? Кроме разве что минимальности кодирования, всё это было уже сказано в топике не по одному разу. MumboКогда используем, например, строку, в качестве переменной-члена класса, то это же привычно и нормально. Да? Безусловно. А когда мы используем строку как приватный член класса только для того, чтобы реализовать в классе методы, допустим, isEmpty(), toInteger(), convertToUtf8(), getIterator() и прочие, взяв их из этой строки, это не очень нормально. Если мы делаем такое, копируя код в разные классы, это тупо. Хотя может быть, кому-то и привычно. В таком случае в принципе можно не реализовывать в классе указанные методы, а сделать метод, возвращающий интерфейс к ним (то есть в Вашем примере - как раз-таки getName()). Это избавляет от тупых переадресаций и в целом скорее лучше, но усложняет код использования. MumboНикто не считает это лишней реализацией (за исключением недопонимающих). Потому что каждый класс занимается своим делом. Точно, каждый занимается своим делом. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.03.2011, 11:26 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
сделайте один класс А с динамическим набором свойств, в конструктор передавайте экземпляр класса Б возвращающий заготовленный набор свойств. если требуется храните в экземпляре его "тип". )) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.03.2011, 11:55 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
Парни! Зачем вы мудрствуете лукаво? Надо плясать от предметной области и от того что было уже разработано. Было: цветная коробка с размерами, обладающая весом (1 класс). Надо: добавить интерфейс получения 6 рисунков с 6 сторон (2-й класс-наследник или поддержка интерфейса). Точка. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.03.2011, 12:24 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
mayton, а если он через час поймет что ему нужно еще припаять какие поля. и закомбинировать с тем что уже имеется? ) имхо динамический набор именнованных пропертей спасёт ТС) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.03.2011, 12:28 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
Если он вносит фундаментальные изменения в задачу "через каждый час" то его не спасёт и множественное наследование интерфейсов. Мне непонятно и нелогично наблюдать класс где добавление очередного интерфейса - это прихоть. Так ничего не проектируется. Давайте дружно вспомним бритву оккама и будем более скромны в постановках и прочих "хотелках". ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.03.2011, 12:58 |
|
||
|
Как правильно наследовать?
|
|||
|---|---|---|---|
|
#18+
softwarerВаш пост, если убрать воду, Ну какую еще воду? Зачем такие наезды? Razel задал вопрос, я ответил ему подробно. Вы что без наездов не можете что-ли обосновать свои возражения? softwarerс для описания наборов характеристик следует использовать интерфейсы да, конечно softwarer для каждого интерфейса нужна стандартная реализация этого я не утверждал. в общем случае возможно, что таких реализаций будет несколько, и в них будет заложено разное поведение softwarer оконечные классы должны включать эту реализацию и переадресовывать ей запросы, схема наследования оконечных классов строится исходя из минимальности кодирования. да, агрегировать реализацию (возможно, через ссылку на ее интерфейс) softwarerВы правда уверены, что это неожиданные и ценные находки? Кто вам сказал что здесь были представлены некие неожиданные находки? Я не изобретал никаких велосипедов, композиция - известная вещь. softwarer А когда мы используем строку как приватный член класса только для того, чтобы реализовать в классе методы, допустим, isEmpty(), toInteger(), convertToUtf8(), getIterator() и прочие, взяв их из этой строки, это не очень нормально. Если мы делаем такое, копируя код в разные классы, это тупо. Хотя может быть, кому-то и привычно. Такого никто не предлагал, это какие-то фантазии или иллюзии. Предлагалось сделать классы под задачу ПоддержкаЦветности, ПоддержкаВесомости и использовать эти классы по их прямому назначению. Не ставить их в зависимость от Ящиков, но Ящики оснастить ими. softwarerможно не реализовывать в классе указанные методы, а сделать метод, возвращающий интерфейс к ним (то есть в Вашем примере - как раз-таки getName()). Это избавляет от тупых переадресаций и в целом скорее лучше, но усложняет код использования. В своем исходном сообщении я указывал на возможность просто выдавать имплементатор при запросе интерфейса. А с другой стороны, при необходимости, вполне возможно использовать перевызовы, и не надо впадать в крайности фанатизма и обзывать их тупыми. Хорошо известен принцип: Композиция предпочтительнее наследования реализации. Если можно свести задачу к композиции реализаций - то это следует делать. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.03.2011, 17:28 |
|
||
|
|

start [/forum/topic.php?fid=16&msg=37151490&tid=1343091]: |
0ms |
get settings: |
10ms |
get forum list: |
13ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
154ms |
get topic data: |
8ms |
get forum data: |
2ms |
get page messages: |
56ms |
get tp. blocked users: |
1ms |
| others: | 245ms |
| total: | 495ms |

| 0 / 0 |
