powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Как правильно наследовать?
25 сообщений из 30, страница 1 из 2
Как правильно наследовать?
    #37151057
Raziel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Предположим у нас есть некий класс (C#):
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
class Box
{
	public uint Width { get; set; }
	public uint Height { get; set; }
	public uint Depth { get; set; }

	public Box(uint width, uint height, uint depth)
	{
		Width = width;
		Height = height;
		Depth = depth;
	}
}
И 2 его предка:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
class ColorBox : Box
{
	public Color ForeColor { get; set; }

	public ColorBox(uint width, uint height, uint depth, Color foreColor)
		: base(width, height, depth)
	{
		ForeColor = foreColor;
	}
}

class SolidBox : Box
{
	public uint Weight { get; set; }

	public SolidBox(uint width, uint height, uint depth, uint weight)
		: base(width, height, depth)
	{
		Weight = weight;
	}
}

Все 3 класса используются в программе.
И тут мне потребовался класс "цветная коробка, обладающая весом". И ещё один - "цветная коробка, обладающая весом и с рисунком на каждой стороне". Как в данном случае правильно срефакторить и создать новые классы?
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37151354
Фотография ZyK_BotaN
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
а зачем здесь наследование?
покажи контекст использования - тогда поразмышляем. а пока я вижу совершенно разные типы, между собой не связанные.
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37151490
Raziel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Это пример.
Есть класс №1 с набором свойств и методов. Есть классы №2 и №3, расширяющие класс №1. И вот возникает ситуация, что нужен класс №4, который бы включал в себя функциональность классов №1, №2, №3 и добавлял что-то своё.
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37151719
Фотография ZyK_BotaN
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RazielЭто пример.
Есть класс №1 с набором свойств и методов. Есть классы №2 и №3, расширяющие класс №1. И вот возникает ситуация, что нужен класс №4, который бы включал в себя функциональность классов №1, №2, №3 и добавлял что-то своё.

Опять, ты приводишь в качестве задачи - реализацию. а придумай сначала задачу где одним из очевидных(возможных) решений являлась бы такая иерархия классов. И тогда я(и возможно другие члены форума) бы с удовольствием решил как это обойти.

а пока ответ один: Не делай больше так.
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37151744
Фотография softwarer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RazielКак в данном случае правильно срефакторить и создать новые классы?
Ну, вообще-то в данном случае правильно использовать множественное наследование. Но поскольку убогие инструменты требуют как-то выкручиваться, придётся использовать не наследование.

Тупой, но иногда "просто и сердито" метод - реализовать необходимый функционал в базовом классе, но открывать только в некоторых потомках. Скажем, сделать методы Get/SetWeight как protected в Box, а также сделать включающий их интерфейс Solid.

Правильный в общем случае метод - сделать класс со смыслом "контейнер-носитель" и некоторое количество "плагинов" к нему. То есть "цветная коробка с весом" будет состоять из "коробки", плагина "цвет" и плагина "вес".
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37152806
Фотография VSVLAD
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Множественного наследования не существует, не применяя магию в виде правки IL кода. В интернете пишут, что лучше использовать интерфейсы чтобы как-то реализовать оба класса.
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37152936
Raziel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А как попроще реализовать эти плагины?
Интерфейсы тут наврядли помогут. Разве что реализации выносить в отдельные классы, а в самой иерархии их просто дёргать. Как-то не очень...
Вообще есть какой-нить паттерн на данную ситуацию?
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37153205
Фотография VSVLAD
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37153282
Фотография softwarer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
RazielИнтерфейсы тут наврядли помогут. Разве что реализации выносить в отдельные классы, а в самой иерархии их просто дёргать. Как-то не очень...
В дельфе есть такая полезная директива implements. Выглядит примерно так:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
 type 
   { Некий интерфейс } 
  IMyInterface =  interface 
    ...
   end ;

   { Класс, его реализующий } 
  TMyObject =  class  ( ..., IMyInterface)
    ...
   end ;

   { Основной класс } 
  TMyMainObject =  class  ( ..., IMyInterface)
    MyObject: TMyObject;
     property  MyInterface: TMyObject read MyObject implements IMyInterface;
       { Реализация IMyInterface берётся из MyObject } 
   end ;

В таких случаях просто спасает. Посмотрите, может в C# есть что-нибудь подобное.
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37153290
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Raziel... И тут мне потребовался класс "цветная коробка, обладающая весом". И ещё один - "цветная коробка, обладающая весом и с рисунком на каждой стороне". Как в данном случае правильно срефакторить и создать новые классы?
Если потребовался - сделай сразу. Впихни все свойства и методы. Если
вопрос стоит так что нужно "заложить возможность в будущем добавлять
функционал" - то для этого можно надстроить много надстроек вплоть
до "списков свойств". (Никто ведь не ограничивает верно?).
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37153353
Фотография ZyK_BotaN
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
VSVLAD Декоратор

просто декоратора не хватит, придется все свойства в одном списке хранить.
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37154433
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
softwarerRazielИнтерфейсы тут наврядли помогут. Разве что реализации выносить в отдельные классы, а в самой иерархии их просто дёргать. Как-то не очень...
В дельфе есть такая полезная директива implements. Выглядит примерно так:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
 type 
   { Некий интерфейс } 
  IMyInterface =  interface 
    ...
   end ;

   { Класс, его реализующий } 
  TMyObject =  class  ( ..., IMyInterface)
    ...
   end ;

   { Основной класс } 
  TMyMainObject =  class  ( ..., IMyInterface)
    MyObject: TMyObject;
     property  MyInterface: TMyObject read MyObject implements IMyInterface;
       { Реализация IMyInterface берётся из MyObject } 
   end ;

В таких случаях просто спасает. Посмотрите, может в C# есть что-нибудь подобное.

В языках без множественного наследования (сишарп, дельфа, ява, ди) есть интерфейсы.
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37156119
Фотография softwarer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SiemarglВ языках без множественного наследования (сишарп, дельфа, ява, ди) есть интерфейсы.
Офигеть, какая неожиданная, ценная и актуальная информация.
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37156134
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
softwarerSiemarglВ языках без множественного наследования (сишарп, дельфа, ява, ди) есть интерфейсы.
Офигеть, какая неожиданная, ценная и актуальная информация.... которые заменяют задачи множественного наследования )
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37156328
Фотография Mumbo
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Можно посмотреть на дело немного иначе.
Начать не с иерархии коробок, а с интерфейсов.
Тут видятся следующие 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]
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37156436
Фотография softwarer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Mumbo[3] ПоддержкаВесящего - может управляться контроллером весящего
Mumbo, это всё как бы очевидно. Проблема в том, что когда весящими должны быть 10 разных классов, делать 10 реализаций как бы тупо, а делать 10 тупых переадресаций на одну реализацию немногим умнее. Наследование классов и implements - два метода, позволяющие обойтись без копирования, поэтому именно их хочется использовать в подобных случаях.
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37156500
Фотография ZyK_BotaN
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
softwarerделать 10 реализаций как бы тупо,

согласен.
softwarerа делать 10 тупых переадресаций на одну реализацию немногим умнее.
не согласен.
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37156554
Gys
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Gys
Гость
В С++ все легко решается с помощью множественого наследования с виртуальным базовым классом, в С# хз...онли интерфейс наверно.
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37156576
Фотография Mumbo
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
softwarerMumbo[3] ПоддержкаВесящего - может управляться контроллером весящего
Mumbo, это всё как бы очевидно. Проблема в том, что когда весящими должны быть 10 разных классов, делать 10 реализаций как бы тупо, а делать 10 тупых переадресаций на одну реализацию немногим умнее. Наследование классов и implements - два метода, позволяющие обойтись без копирования, поэтому именно их хочется использовать в подобных случаях.
softwarer, оборот "это всё как бы очевидно" - это похоже на тупое фиглярство и понты. А это все никому не нужно, так что давайте лучше разберемся.

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

Когда используем кроме переменной класса Строка еще и переменную класса Вектор, а также переменную класса Дерево, и переменные разных других классов это тоже привычно и нормально. Никто не считает это лишней реализацией (за исключением недопонимающих). Потому что каждый класс занимается своим делом.

Аналогично и в рассмотренном примере. Переменные классов ПоддержкаЦветного и ПоддержкаВесящего - это аналоги переменной класса Строка, переменной класса Вектор. С тем небольшим отличием, что они могут поддерживать (если надо) еще и управление со стороны внешнего контроллера.
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37157028
Фотография softwarer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Mumbosoftwarer, оборот "это всё как бы очевидно" - это похоже на тупое фиглярство и понты. А это все никому не нужно, так что давайте лучше разберемся.
Давайте разберёмся. Ваш пост, если убрать воду, сводится к четырём мыслям: для описания наборов характеристик следует использовать интерфейсы, для каждого интерфейса нужна стандартная реализация, оконечные классы должны включать эту реализацию и переадресовывать ей запросы, схема наследования оконечных классов строится исходя из минимальности кодирования. Вы правда уверены, что это неожиданные и ценные находки? Кроме разве что минимальности кодирования, всё это было уже сказано в топике не по одному разу.

MumboКогда используем, например, строку, в качестве переменной-члена класса, то это же привычно и нормально. Да?
Безусловно. А когда мы используем строку как приватный член класса только для того, чтобы реализовать в классе методы, допустим, isEmpty(), toInteger(), convertToUtf8(), getIterator() и прочие, взяв их из этой строки, это не очень нормально. Если мы делаем такое, копируя код в разные классы, это тупо. Хотя может быть, кому-то и привычно.

В таком случае в принципе можно не реализовывать в классе указанные методы, а сделать метод, возвращающий интерфейс к ним (то есть в Вашем примере - как раз-таки getName()). Это избавляет от тупых переадресаций и в целом скорее лучше, но усложняет код использования.

MumboНикто не считает это лишней реализацией (за исключением недопонимающих). Потому что каждый класс занимается своим делом.
Точно, каждый занимается своим делом.
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37157128
Фотография J.d
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
сделайте один класс А с динамическим набором свойств,
в конструктор передавайте экземпляр класса Б возвращающий заготовленный набор свойств.
если требуется храните в экземпляре его "тип".

))
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37157219
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Парни! Зачем вы мудрствуете лукаво? Надо плясать от предметной
области и от того что было уже разработано.

Было: цветная коробка с размерами, обладающая весом (1 класс).

Надо: добавить интерфейс получения 6 рисунков с 6 сторон (2-й класс-наследник или поддержка интерфейса).

Точка.
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37157233
Фотография J.d
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,

а если он через час поймет что ему нужно еще припаять какие поля. и закомбинировать с тем что уже имеется? )
имхо динамический набор именнованных пропертей спасёт ТС)
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37157338
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если он вносит фундаментальные изменения в задачу "через каждый час" то
его не спасёт и множественное наследование интерфейсов.

Мне непонятно и нелогично наблюдать класс где добавление очередного
интерфейса - это прихоть. Так ничего не проектируется.

Давайте дружно вспомним бритву оккама и будем более скромны
в постановках и прочих "хотелках".
...
Рейтинг: 0 / 0
Как правильно наследовать?
    #37158104
Фотография Mumbo
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
softwarerВаш пост, если убрать воду,
Ну какую еще воду? Зачем такие наезды? Razel задал вопрос, я ответил ему подробно. Вы что без наездов не можете что-ли обосновать свои возражения?

softwarerс для описания наборов характеристик следует использовать интерфейсы
да, конечно

softwarer для каждого интерфейса нужна стандартная реализация
этого я не утверждал. в общем случае возможно, что таких реализаций будет несколько, и в них будет заложено разное поведение

softwarer оконечные классы должны включать эту реализацию и переадресовывать ей запросы, схема наследования оконечных классов строится исходя из минимальности кодирования.
да, агрегировать реализацию (возможно, через ссылку на ее интерфейс)

softwarerВы правда уверены, что это неожиданные и ценные находки?
Кто вам сказал что здесь были представлены некие неожиданные находки? Я не изобретал никаких велосипедов, композиция - известная вещь.

softwarer А когда мы используем строку как приватный член класса только для того, чтобы реализовать в классе методы, допустим, isEmpty(), toInteger(), convertToUtf8(), getIterator() и прочие, взяв их из этой строки, это не очень нормально. Если мы делаем такое, копируя код в разные классы, это тупо. Хотя может быть, кому-то и привычно.


Такого никто не предлагал, это какие-то фантазии или иллюзии. Предлагалось сделать классы под задачу ПоддержкаЦветности, ПоддержкаВесомости и использовать эти классы по их прямому назначению. Не ставить их в зависимость от Ящиков, но Ящики оснастить ими.

softwarerможно не реализовывать в классе указанные методы, а сделать метод, возвращающий интерфейс к ним (то есть в Вашем примере - как раз-таки getName()). Это избавляет от тупых переадресаций и в целом скорее лучше, но усложняет код использования.

В своем исходном сообщении я указывал на возможность просто выдавать имплементатор при запросе интерфейса. А с другой стороны, при необходимости, вполне возможно использовать перевызовы, и не надо впадать в крайности фанатизма и обзывать их тупыми.

Хорошо известен принцип: Композиция предпочтительнее наследования реализации. Если можно свести задачу к композиции реализаций - то это следует делать.
...
Рейтинг: 0 / 0
25 сообщений из 30, страница 1 из 2
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Как правильно наследовать?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]