Наследование.. Каким оно бывает?

by Темных Сергей 26.03.2009 16:28:00
Наследование... У наследования есть два разных смысла. Первый смысл: это наследование реализации — новый класс наследует поведение, аттрибуты, реализованные интерфейсы и т.д. от предка.
Второй смысл — это наследование интерфейса — этот термин не совсем правильный (т.к. а что именно мы наследуем при наследовании от интерфейса?). Поэтому правильно говорить, что класс реализует интерфейсы, а не наследуется от них.

Все что я говорил выше про наследовании — это было именно наследование реализации.
У Лисковой, наоборот, говорится про интерфейсы, т.е. если класс наследуется от интерфейса эллипс, то реализация этого наследования должна быть корректной.

Рассмотрим класс "эллипс". Этот класс может обозначать две разные сущности:
1. Элиппс, не являющейся кругом. Или другими словами — это эллипс без вырожденных случаев.
2. Эллипс с учетом всех вырожденных случаев. Фактически такой эллипс должен содержать поведение и для таких вырожденных случаев, как круг, точка и может быть такие вырожденные случаи, как "плоскость"(эллипс бесконечного радиуса), "отрезок" (эллипс нулевой длины и какой-то ширины), "прямая" (эллипс нулевой длины и бесконечного радиуса),
"полоса" (эллипс какой-то ширины и бесконечной длины).

Теперь поговорим об интерфейсах для данного случая.
Интерфейсы получаются следующие:
Не вырожденный эллипс ( 0 < ширина < бесконечность, 0 < высота < бесконечность, ширина != высота)
Круг
"Точка"
"Плоскость"
"Полоса"
"Отрезок"
Обобщенный эллипс

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

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


Компоненты не имеют право, напрямую, ссылаться на типы-реализации (иначе получаем нарушение инкапсуляции и нарушение полиморфизма). Компоненты имеют право только пользоваться вышеприведенными интерфейсами.


Теперь вернемся к наследованию, как я уже вышеупомянул, термин "наследование" в первую очередь означает наследование реализации.

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

Рассмотрим класс-реализацию "круг".
Этот класс содержит 3 реализации интерфейсов: класс-реализация "точка", класс-реализация "круг с операциями из поля круг", класс-реализация "круг с операциями, выводящие из поля круг".

Теперь рассмотрим наследование реализаций.
Наследовать мы можем, как класс-реализацию "круг" от класс-реализации "обобщенный эллипс", так и "обобщенный эллипс" от "круга".

-- наследование класса-реализации "обобщенный эллипс" от класса-реализации "круг" --
Здесь все просто. Обобщенный эллипс добавляет реализацию тех методов, которые не были реализованы в круге.

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


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

Если же нам нужны и интерфейсы второго рода и не достаточно интерфейсов первого рода, то необходимы также и динамической типизации, а также изменение набора поддерживаемых интерфейсов у объекта по ходу работы.

Все текущие индустриальные языки (C++, Java, C#) довольствуются интерфейсами только первого рода, и не поддерживают, напрямую, интерфейсы второго рода.

Оценок нет

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Похожие записи

Powered by BlogEngine.NET 1.3.1.0
Theme by Mads Kristensen

Сергей Темных

Модулятор


Calendar

<<  Октябрь 2017  >>
повтсрчепясуво
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345

View posts in large calendar

Страницы

    Последние комментарии

    Категории

    None


    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

    © Copyright 2017

    Sign in