Взгляд на класс как на модуль

Взгляд на класс как на модуль

С этой точки зрения наследование особенно эффективно в качестве метода повторного использования.

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

Наследование предоставляет эту возможность. Если B является наследником A, то все службы (компоненты) A автоматически доступны в B, и их не нужно в нем явно определять. В соответствии со своими целями B может добавить новые компоненты. Дополнительная гибкость обеспечивается переопределением, позволяющим B по-разному использовать реализации, предлагаемые A: некоторые из них не меняются, а другие переделываются в более подходящие для данного класса версии.

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

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

[x]. Закрытой, поскольку клиентам для выполнения их собственной разработки нужны службы модуля и, будучи один раз зафиксированы в некоторой его версии, они не должны изменяться при введении новых служб, в которых клиент не нуждается.

[x]. Открытой, так как нет никакой гарантии, что с самого начала в модуль были включены все службы, потенциально необходимые некоторому клиенту.

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

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

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

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

Рис. 14.12.  Набросок структуры библиотеки таблиц

Эта диаграмма наследования представляет только набросок, хотя на ней показаны типичные для этих структур связи по наследованию. Систематическую классификацию таблиц и других контейнеров, основанную на наследовании, см. в [M 1994a].

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

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

Следующая глава >

Похожие главы из других книг:

Модуль

Из книги автора

Модуль Модули – это группы элементов, объединенные для создания отдельных блоков по принципу единства формы или функции. Форма регистрации, например, представляет собой модуль, объединяющий множество элементов, – метки поля формы, кнопки и


Модуль UDP

Из книги автора

Модуль UDP Вернемся к рассмотрению ситуации, когда датаграмма адресована нашему хосту, не содержит ошибок (по крайней мере, с точки зрения IP) и должна быть передана транспортному протоколу. Поскольку целью данного раздела является иллюстрация схемы взаимодействия между


Модуль TCP

Из книги автора

Модуль TCP Как следует из предшествующего описания TCP, этот транспортный протокол обеспечивает гораздо более высокое качество передачи, чем UDP. Соответственно, его реализация также является гораздо более сложной. В предыдущих разделах уже встречались различные алгоритмы,


14.9.6. Модуль Etc

Из книги автора

14.9.6. Модуль Etc Модуль Etc получает различную информацию из файлов /etc/passwd и /etc/group. Понятно, что полезен он только на платформе UNIX.Метод getlogin возвращает имя пользователя, от имени которого запущена программа. Если он завершается неудачно, может помочь метод getpwuid (принимающий в


Самый базовый класс MFC (класс CObject)

Из книги автора

Самый базовый класс MFC (класс CObject) Подавляющее большинство классов библиотеки MFC наследовано от базового класса CObject, лежащего в основе всей иерархии классов этой библиотеки. Методы и элементы данных класса CObject представляют наиболее общие свойства наследованных из него


Архивный класс (класс CArchive)

Из книги автора

Архивный класс (класс CArchive) Класс CArchive используется для сохранения и восстановления состояния объектов в файлах на диске. Перед использованием объекта класса CArchive он должен быть привязан к файлу – объекту класса CFile.Более подробно о процессе сохранения и восстановления


Класс CObject – основной класс MFC

Из книги автора

Класс CObject – основной класс MFC Подавляющее большинство классов из библиотеки MFC наследуются от основного класса CObject. Практически все классы, которые используются в ваших приложениях, например CView или CWinApp, унаследованы от класса CObject.Класс CObject обеспечивает наиболее общие


Модуль Timers

Из книги автора

Модуль Timers Модуль Timers содержит класс Timer, позволяющий выполнять определенные действия через равные промежутки времени. В конструкторе класса Timer указывается промежуток времени и имя процедуры без параметров - обработчика события таймера, вызываемой через указанный


Класс как модуль и как тип

Из книги автора

Класс как модуль и как тип В не ОО-подходах концепции модуля и типа существуют независимо друг от друга. Наиболее замечательным свойством класса является одновременное использование обеих концепций в рамках единой лингвистической конструкции. Класс является модулем


Взгляд на класс как на тип

Из книги автора

Взгляд на класс как на тип С точки зрения типов наследование адресуется и к повторному использованию, и к расширяемости, в частности, к тому, что в предыдущем обсуждении называлось непрерывностью. Здесь ключом является динамическое связывание.Тип - это множество