Зачем нужны иерархии реализаций?
От: Alexey Chen Чили  
Дата: 29.06.05 15:50
Оценка:
Пока мы инетересно болтати о виртуальных функциях в С++, как-то незаметно возник у меня филосовсий вопрос

Зачем нужны иерархии реализаций? Не абстракных интерфейсов, а именно полноценных реализаций. Это когда конкретные классы публично наследуются.

Как бы исчерпывающего ответа я не знаю. Так, на пальцах и небольших примерах. Может кто-то обьяснит это фундаментально?
Re: Зачем нужны иерархии реализаций?
От: Кодт Россия  
Дата: 29.06.05 16:21
Оценка: 1 (1) +1
Здравствуйте, Alexey Chen, Вы писали:

AC>Зачем нужны иерархии реализаций? Не абстракных интерфейсов, а именно полноценных реализаций. Это когда конкретные классы публично наследуются.

AC>Как бы исчерпывающего ответа я не знаю. Так, на пальцах и небольших примерах. Может кто-то обьяснит это фундаментально?

Прагматический ответ:
Чтобы всю реализацию [класса-предка] не переписывать [в наследнике] с нуля ради какого-то тюнинга или расширения.

А публичность — чтобы в наследнике не переписывать с нуля интерфейсы предка.
struct IX { ... };
struct IY { ... };

class Base : public IX, public IY
{
public:
  nonvirtual_api();
  ...
};

class Derived_1 : public IX, public IY
{
  Base* impl; // агрегация как альтернатива наследованию
  ...
  // копируем интерфейс и реализацию (хотя бы в виде шлюзов к impl)
};

class Derived_2 : private Base,
  // копируем интерфейс
  public IX, public IY,
  ...
{
public:
  // копируем интерфейс
  using Base::nonvirtual_api();
  ...
};
Перекуём баги на фичи!
Re[2]: Зачем нужны иерархии реализаций?
От: Alexey Chen Чили  
Дата: 29.06.05 16:40
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Прагматический ответ:

К>Чтобы всю реализацию [класса-предка] не переписывать [в наследнике] с нуля ради какого-то тюнинга или расширения.
Не ну это я знаю.... это и есть на пальцах Хочется большого и чистого, но не слона, а такое фундаментальное обьяснение чтобы уж совсем фундаментально. Получается что наследование нужно только лишь для переиспользования кода? И если бы можно было автоматически делегировать вызовы реализуемого интерфейса в агрегат, то наследование было бы не нужно?

К>А публичность — чтобы в наследнике не переписывать с нуля интерфейсы предка.

К>[c]
К>struct IX { ... };
К>struct IY { ... };

Сразу вспоминается старый прикол про то что наследование убивает инкапсуляцию. Вот интересно в строго типизированных языках вообще можно сделать приватное наследование (реализации) с сохранением публичного интерфейса? Нда, сказанул. Это вообще на что может быть похожим?
Re[3]: Зачем нужны иерархии реализаций?
От: Andrei N.Sobchuck Украина www.smalltalk.ru
Дата: 29.06.05 18:47
Оценка:
Здравствуйте, Alexey Chen, Вы писали:

AC>Получается что наследование нужно только лишь для переиспользования кода? И если бы можно было автоматически делегировать вызовы реализуемого интерфейса в агрегат, то наследование было бы не нужно?


Наследование реализации нужно именно для переиспользования кода. Делегирование вызовов это и есть наследование реализации.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Я ненавижу Hibernate
Автор: Andrei N.Sobchuck
Дата: 08.01.08
!
Re[4]: Зачем нужны иерархии реализаций?
От: Alexey Chen Чили  
Дата: 29.06.05 19:36
Оценка:
Здравствуйте, Andrei N.Sobchuck, Вы писали:

AC>>Получается что наследование нужно только лишь для переиспользования кода? И если бы можно было автоматически делегировать вызовы реализуемого интерфейса в агрегат, то наследование было бы не нужно?

ANS>Наследование реализации нужно именно для переиспользования кода. Делегирование вызовов это и есть наследование реализации.

Хм, то есть широко известный критерй мадам Лисков отступает перед прагматикой? Или как?
Иначе говоря, иерархия наследования реализаций есть ни что иное как фабрика модулей.

Интересно вот стало, а что такое вообще наследование? Что об этом говорят классики?
И как это сочитается с наследованием реализации для переиспользования?
Re[5]: Зачем нужны иерархии реализаций?
От: Кодт Россия  
Дата: 29.06.05 20:41
Оценка: :))) :)
Здравствуйте, Alexey Chen, Вы писали:

AC>Иначе говоря, иерархия наследования реализаций есть ни что иное как фабрика модулей.


Нееет! Только не это, шеф! Только не модульность, только не оберон. Va-bene
Перекуём баги на фичи!
Re[3]: Зачем нужны иерархии реализаций?
От: Кодт Россия  
Дата: 29.06.05 20:54
Оценка:
Здравствуйте, Alexey Chen, Вы писали:

К>>Прагматический ответ:

К>>Чтобы всю реализацию [класса-предка] не переписывать [в наследнике] с нуля ради какого-то тюнинга или расширения.
AC>Не ну это я знаю.... это и есть на пальцах Хочется большого и чистого, но не слона, а такое фундаментальное обьяснение чтобы уж совсем фундаментально. Получается что наследование нужно только лишь для переиспользования кода? И если бы можно было автоматически делегировать вызовы реализуемого интерфейса в агрегат, то наследование было бы не нужно?

К>>А публичность — чтобы в наследнике не переписывать с нуля интерфейсы предка.

К>>[c]
К>>struct IX { ... };
К>>struct IY { ... };

AC>Сразу вспоминается старый прикол про то что наследование убивает инкапсуляцию. Вот интересно в строго типизированных языках вообще можно сделать приватное наследование (реализации) с сохранением публичного интерфейса? Нда, сказанул. Это вообще на что может быть похожим?


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

Но каким бы затейливым способом не было всё это сделано (наследование, агрегирование, делегирование, чёрт в ступе) снаружи это всё равно будет выглядеть в соотвествии с Лисковой. Если один такой клубок тесно связанных объектов можно заменить другим клубком — то эти клубки выступают в отношении суперкласс-субкласс.
Перекуём баги на фичи!
Re[3]: Зачем нужны иерархии реализаций?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 30.06.05 14:19
Оценка:
Здравствуйте, Alexey Chen, Вы писали:

AC>Не ну это я знаю.... это и есть на пальцах Хочется большого и чистого, но не слона, а такое фундаментальное обьяснение чтобы уж совсем фундаментально. Получается что наследование нужно только лишь для переиспользования кода? И если бы можно было автоматически делегировать вызовы реализуемого интерфейса в агрегат, то наследование было бы не нужно?


В принципе да. Если есть отдельно наследование только интерфейсов и наследование только реализаций, то без классического наследования вполне можно прожить.
... << RSDN@Home 1.2.0 alpha rev. 505>>
AVK Blog
Re[4]: Зачем нужны иерархии реализаций?
От: Alexey Chen Чили  
Дата: 30.06.05 15:02
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, Alexey Chen, Вы писали:


AC>>Не ну это я знаю.... это и есть на пальцах Хочется большого и чистого, но не слона, а такое фундаментальное обьяснение чтобы уж совсем фундаментально. Получается что наследование нужно только лишь для переиспользования кода? И если бы можно было автоматически делегировать вызовы реализуемого интерфейса в агрегат, то наследование было бы не нужно?


AVK>В принципе да. Если есть отдельно наследование только интерфейсов и наследование только реализаций, то без классического наследования вполне можно прожить.


Да можно конечно. Только ведь так делают очень редко. Часто бывает совмещение интерфейса и реализации в одном дереве. И интерфейсы то часто бывают статические. Вот нигде не видел понятного обьяснения почему что-то делают так, а что-то иначе. Всё сводится к 'жопой чуствую что верно'. Но это же ведь не аргумент. Когда я пишу код, перед мной всегда стоит выбор из нескольких вариантов. И думаю, каждый с этим сталкивается, но нормального критеория кроме, 'когда-то я делел так и мне понравилось'.... вообще-то нету, такого.

Или у кого есть?

Вот к примеру, что-то типа


совершенно абстракный пример, просто демонстрирующий идею

struct Base
  {
    virtual DoIt();
  }  
struct Derived1 : Base
  {
    DoIt()
      {
        // bla-bla-bla
        Base::DoIt()
      }
  }  
struct Derived2 : Derived1
  {
    DoIt()
      {
        // bla-bla-bla
        Derived1::DoIt()
      }
  }


Почему и зачем используется именно иерархия классов совмещяющих в себе реализацию и интерфейс при этом использующая для рализации логики публичный интерфейс базы? Это ведь даже правильно, в том смысле что не разрушает инкапсуляцию, но почему именно наследовние реализации? Что является тем агрументом который влияет на выбор такого или какого-то иного решения?

Один из критериев уже предложил Максим (jazzer) — отношение 'is-a'. Но опять же, это ведь только критерий допустимости. Или нет?
Re[5]: Зачем нужны иерархии реализаций?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 30.06.05 15:23
Оценка:
Здравствуйте, Alexey Chen, Вы писали:

AC>Да можно конечно. Только ведь так делают очень редко. Часто бывает совмещение интерфейса и реализации в одном дереве.


Тем не менее качественные реализации тяготеют все же к вынесению модели. МС вот правда это ну очень не любит делать, отделяемые модели в фреймворке к примеру можно пересчитать по пальцам одной руки. В вот в Java для всех относительно свежих стандартов это норма.
... << RSDN@Home 1.2.0 alpha rev. 505>>
AVK Blog
Re[4]: Зачем нужны иерархии реализаций?
От: Alexey Chen Чили  
Дата: 30.06.05 15:24
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Мнэээ. Кроме прочего, наследование предоставляет базовому классу интерфейс реализации (виртуальные функции, перекрытые у потомка).


Имеется в виду 'шаблонная функция'? Я предлагаю хоть частично пользоваться доступной терминологией, ну хотябы из тех облостей ОО в которых она вообще существует, более менее известна, и хоть как-то устоялось в нашем сообществе. Книгу от GoF, всёравно все читали. Как впрочем и Буча, но у него терминалогия нстолько расмыта, что ею пользоваться надо ну очнь осторожно.

К>Разумеется, то же самое можно добиться и при агрегировании: отдать агрегату ссылку на реализацию внутренних фич (необязательно на себя, кстати).

Вот мне и интересно, почему (и когда) выбор падает на наследование и 'шаблонную функцию', а не на декоратора, стратегии или наблюдателя (сигналы)? К примеру при добавлении к сообщению заголовка или обработке OnClick.

Как бы ясно, что есть противопоставление, обьекта как монолитной матрёшки сущностей и как композита заменяемых слабосвязанных и самодостаточных элементов. Но не понятен критерий выбора.
Re[6]: Зачем нужны иерархии реализаций?
От: Alexey Chen Чили  
Дата: 30.06.05 15:27
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Тем не менее качественные реализации тяготеют все же к вынесению модели. МС вот правда это ну очень не любит делать, отделяемые модели в фреймворке к примеру можно пересчитать по пальцам одной руки. В вот в Java для всех относительно свежих стандартов это норма.


Может проблема в сложности управления жизненым циклом на C++ (шарпом я не очень интересуюсь) ?
Re[7]: Зачем нужны иерархии реализаций?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 30.06.05 15:39
Оценка:
Здравствуйте, Alexey Chen, Вы писали:

AVK>>Тем не менее качественные реализации тяготеют все же к вынесению модели. МС вот правда это ну очень не любит делать, отделяемые модели в фреймворке к примеру можно пересчитать по пальцам одной руки. В вот в Java для всех относительно свежих стандартов это норма.


AC>Может проблема в сложности управления жизненым циклом на C++ (шарпом я не очень интересуюсь) ?


Нет, проблема в том что МС сильно не любит сторонних реализаций. В примеру, если ты напишешь свой XML парсер, то весь повязанный на XML код с ним работать не сможет, так как совместимость по типам ты обеспечить не сможешь, только на уровне исходников.
... << RSDN@Home 1.2.0 alpha rev. 505>>
AVK Blog
Re[5]: Зачем нужны иерархии реализаций?
От: Кодт Россия  
Дата: 30.06.05 16:28
Оценка:
Здравствуйте, Alexey Chen, Вы писали:

К>>Мнэээ. Кроме прочего, наследование предоставляет базовому классу интерфейс реализации (виртуальные функции, перекрытые у потомка).


AC>Имеется в виду 'шаблонная функция'? Я предлагаю хоть частично пользоваться доступной терминологией, ну хотябы из тех облостей ОО в которых она вообще существует, более менее известна, и хоть как-то устоялось в нашем сообществе. Книгу от GoF, всёравно все читали. Как впрочем и Буча, но у него терминалогия нстолько расмыта, что ею пользоваться надо ну очнь осторожно.


Как бы. Паттерн "Шаблонная функция" — это то, что достигается посредством интерфейса реализации. Т.е. есть инструмент и есть практика его использования.
В какой-то степени (особенно, когда шаблонная функция вырождена) тут возникают другие паттерны — например, адаптер.
Базовый подобъект является шлюзом между пользователем и целым объектом-наследником.

К>>Разумеется, то же самое можно добиться и при агрегировании: отдать агрегату ссылку на реализацию внутренних фич (необязательно на себя, кстати).

AC>Вот мне и интересно, почему (и когда) выбор падает на наследование и 'шаблонную функцию', а не на декоратора, стратегии или наблюдателя (сигналы)? К примеру при добавлении к сообщению заголовка или обработке OnClick.

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

AC>Как бы ясно, что есть противопоставление, обьекта как монолитной матрёшки сущностей и как композита заменяемых слабосвязанных и самодостаточных элементов. Но не понятен критерий выбора.


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

Далее выясняется, что если есть иерархия классов, то физическим наследованием её реализовать проще. Хотя нас никто не обязывает: могут быть совершенно разнородные объекты, скрывающиеся за одинаковыми интерфейсами.

Пример: окна. Есть некая "натуральная" классификация (контролы, диалоги, фреймы и т.д.), причём можно эту иерархию воспроизвести буквально (скажем, кроссплатформенные оконные системы), а можно развести зоопарк (как это принято в Windows).
Поскольку виндоуз ориентирован на низкоуровневые и разнородные языки, физическое наследование невозможно. И оно заменяется "шнуровкой".
Перекуём баги на фичи!
Re[6]: Зачем нужны иерархии реализаций?
От: Alexey Chen Чили  
Дата: 30.06.05 16:37
Оценка: +2
Здравствуйте, Кодт, Вы писали:

К>Наследование в прагматическом виде — это

реализации

К>- берём базовый подобъект

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

Прочитал... пришла в голову идея. Наследование реализации — простейший структурный паттерн роддерживаемый на уровне языка (в большенстве OO языков)
Re[6]: Зачем нужны иерархии реализаций?
От: Alexey Chen Чили  
Дата: 30.06.05 17:08
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Шаблонная функция (имхо) есть обобщение тех же декораторов, наблюдателей и стратегий. Когда возникает некое

Ну, в общем я так же думаю

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


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

Прочитал то что написал, и подумал:
Если при этом чуть-чуть забыть о слове наследование, то хорошо видно, что критери is-a для наследования релизации не работает. Задача у такого наследования другая. Это я к тому, что правильно ли говорить — я унаследовал (реализацию) потому, что наследник это тоже самое? Сдаётся мне, что это ни есть причина, причина была указана в твоём постинге.
Re[7]: Зачем нужны иерархии реализаций?
От: Кодт Россия  
Дата: 30.06.05 17:34
Оценка:
Здравствуйте, Alexey Chen, Вы писали:

К>>Шаблонная функция (имхо) есть обобщение тех же декораторов, наблюдателей и стратегий. Когда возникает некое

AC>Ну, в общем я так же думаю

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


AC>При наследовании: начальник это наследник, подчинённый — база?


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

О! Кстати говоря: наследование это структурный паттерн, а ш.ф. — функциональный. Вполне естественно, что некоторые структурные и функциональные паттерны тяготеют друг к другу.

AC>Получается, что когда у начальника может быть подчинённый только одного типа (и/или ему требуется знание устройства подчинённого) и существуют они только вместе, то наследование реализации оптимальным образом обеспечивает такую связь. Да, логично. Плюсы очевидны, минус сильной сязи не важен — решение действительно хорошее.


В паттерне ш.ф. наоборот: подчинённый полиморфен.
Однако да, есть такие ситуации, при которых тип подчинённого фиксируется.
Впрочем, "начальник" и "подчинённый" — это роли. По ходу дела части объекта могут меняться ролями: например, некоторый интерфейс реализован в базе (которая обращается за реализацией к наследнику), а другой интерфейс появляется только у наследника (который пользуется базой).

AC>Прочитал то что написал, и подумал:

AC>Если при этом чуть-чуть забыть о слове наследование, то хорошо видно, что критери is-a для наследования релизации не работает. Задача у такого наследования другая. Это я к тому, что правильно ли говорить — я унаследовал (реализацию) потому, что наследник это тоже самое? Сдаётся мне, что это ни есть причина, причина была указана в твоём постинге.

По-моему, мы уже озвучивали эту мысль на форуме. Наследование и принадлежность (что такое субкласс: это подмножество некоего суперкласса) — различаются, причём наследник может как сузить класс, так и, наоборот, расширить.
Трактовка наследника как субкласса удобна для формального контроля типов (неявный down-casting). Однако наследник может по смыслу "не вписаться" в контракт предка; самый известный пример — это срезка при копировании.
Перекуём баги на фичи!
Re: Они не нужны
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 01.07.05 09:48
Оценка:
Здравствуйте, Alexey Chen, Вы писали:

AC>Зачем нужны иерархии реализаций? Не абстракных интерфейсов, а именно полноценных реализаций. Это когда конкретные классы публично наследуются.


Они и не нужны. Вполне достаточно иметь иерархии абстрактных типов. Многократно переопределяемые методы тоже не нужны, достаточно иметь однократно определяемые абстрактные или пустые методы. Просто в абстрактном типе определяете абстрактный или пустой метод, а в каком-то из абстрактных же типов расширений этот метод определяете (однократно!!!) тогда когда понимаете, что в последующих расширениях это метод уже не будет изменяться так сказать "финализирован" один раз и навсегда. Добавлю к этому еще то что тип может быть объявлен абстрактным даже в том случае если у него нет (никогда не было или уже нет, поскольку они уже определены) абстрактных или пустых методов. Расширять конкретный тип смысла нет никакого — бери и создавай его объекты и устраивай композицию объектов. Не верьте тому кто скажет, что данный совет может привести к дублированию кода. Нет не может. Просто программировать надо уметь.
Re[2]: Они не нужны
От: Кодт Россия  
Дата: 01.07.05 11:35
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

AC>>Зачем нужны иерархии реализаций? Не абстракных интерфейсов, а именно полноценных реализаций. Это когда конкретные классы публично наследуются.


СГ>Они и не нужны. <далее идёт описание технологии>. Просто программировать надо уметь.


Так ведь и вопрос-то был в том: зачем нужны иерархии реализаций, если и без них можно обойтись.
Ответ: затем, чтобы упростить жизнь разработчику, когда наследование реализации возможно и эффективно.
(В ряде случаев — например, в COM — оно невозможно; в ряде случаев — неэффективно).
Перекуём баги на фичи!
Re[3]: Зачем нужны иерархии реализаций?
От: alexeiz  
Дата: 02.07.05 22:52
Оценка:
"Alexey Chen" wrote:
> Сразу вспоминается старый прикол про то что наследование убивает
> инкапсуляцию.

Каким это образом наследование убивает инкапсуляцию? Если у тебя базовый класс инкапсулирует внутренности private доступом, то никаким образом ты не расширишь доступ в наследуемом классе. А вот если ты взял за правило использовать protected, то конечно унаследованному классу все становится открыто.
Posted via RSDN NNTP Server 1.9
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.