double arrow

Предотвращение наследования с помощью ключевого слова sealed

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

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

sealed class X{…}

class Y:X // Наследование от класса X невозможно

{

}

А так закрывается для переопределения функция–член класса:

class X

{

sealed public void f(){…}

}

class Y:X

{

public void f(){…}// Наследование метода f(), объявленного в классе X запрещено!

}

Отношения между классами

Использование наследования позволяет реализовать множество самых разных отношений между классами. Однако всех их можно условно разделить на две большие группы: отношения, определяемые классическим наследованием, и отношения агрегирования.

Первая группа отношений основана на использовании классического наследования, когда один класс может рассматриваться как некоторая модификация другого класса. В результате, отношения между классами строятся по принципу ("is-a"). То есть один класс – родительский (главный), а второй – дочерний (подчиненный). В этом случае без участия родительского класса невозможно будет реализовать и дочерний класс. Таким образом, классы А и В находятся в отношении наследования, если, при объявлении класса В, класс А указан в качестве родительского класса. Такое определение позволяет устанавливать отношения между родительскими классами и их наследниками.

Вторая группа отношений между классами строится на использовании принципа вложенности, когда один класс содержит ("has a") в своем составе экземпляр другого класса. Отношения агрегирования (вложенности) реализуются путем размещения (локализации) класса или его экземпляра внутри владеющего класса и передачи (делегирования) части своих полномочий вложенному классу или его экземпляру. В этом случае владеющий класс, выглядит как контейнер, содержащий в себе экземпляры других классов которым он поручает выполнение части своих функциональных возможностей. Другими словами, если существуют классы для построения объектов, способных выполнять какую-то часть функций класса-контейнера, то он включает их в свой состав и делегирует им выполнение соответствующей части своих полномочий. Если же среди доступных классов нет подходящих, тогда класс контейнер может самостоятельно создать внутри себя такой класс (вложенный класс) и использовать его экземпляр в качестве своей внутренней переменной, которой делегируется выполнение части своих функций. Формальное определение отношения агрегирования можно выглядеть следующим образом: классы А и В находятся в отношении вложенности, если одним из полей класса В является класс А или его экземпляр. Данное определение позволяет задавать отношения агрегирования между классами в виде двух его форм: вложенности и владения.

Следует отметить, что отношения наследования и вложенности - являются транзитивными. Если класс В является наследником класса А, а класс С является наследником класса В, то класс С также является и наследником класса А. Если класс А или его экземпляр является составной (вложенной) частью класса В, а класс В или его экземпляр является составной (вложенной) частью класса С, то класс А или его экземпляр также является и составной (вложенной) частью класса С.

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

На практике вполне могут встречаться довольно длинные цепочки отношений между классами и их экземплярами. Например, библиотечные классы, составляющие систему Microsoft Office, полностью построены на отношении вложенности. При программной работе с объектами Word можно начать с объекта, задающего приложение Word, и добраться до объекта, задающего отдельный символ в некотором слове некоторого предложения одного из открытых документов. Для выбора нужного объекта можно задать такую цепочку: приложение Word: коллекция документов - документ - область документа - совокупность абзацев - абзац - совокупность предложений - предложение - набор слов - слово - набор символов - символ. В этой цепочке каждому понятию соответствует свой класс библиотеки Microsoft Office, где каждая пара соседствующих классов связана отношением вложенности.

Классы библиотеки FCL связаны как отношением вложенности, так и отношением наследования. Длинные цепочки наследования и вложенности достаточно характерны для классов этой библиотеки.

При проектировании классов часто возникает вопрос, какое же отношение между классами нужно построить. Рассмотрим совсем простой пример двух классов - Square и Rectangle, описывающих квадраты и прямоугольники. Наверное, понятно, что эти классы следует связать скорее отношением наследования, чем вложенности; менее понятным остается вопрос, а какой из этих двух классов следует сделать родительским. Еще один пример двух классов, описывающих легковой автомобиль и человека. Какими отношениями должны быть связаны эти классы с другим классом, например, с классом владельца автомобиля? Может ли он быть наследником обоих классов? Найти правильные ответы на эти вопросы проектирования классов помогает понимание того, что отношение вложенности (или владения) задает отношение "имеет" ("has а"), а отношение наследования задает отношение "является" ("is a"). В случае классов квадрата и прямоугольника понятно, что каждый объект квадрата "является" прямоугольником, поэтому между их классами имеет место отношение наследования, и родительским классом является класс прямоугольника, а класс квадрата (как частный случай прямоугольника) является его потомком.

В случае автомобилей, людей и владельцев авто также понятно, что владелец "является" человеком и "имеет" автомобиль. Поэтому класс владельца автомобиля является владельцем объекта класса автомобиля и наследником класса человека.


Сейчас читают про: