Главная » Java » Расширение классов: когда и как

0

Возможность создания расширенных классов — одно из главных достоинств объектно- ориентированного  программирования.  Когда вы расширяете класс, чтобы наделить его новыми функциями, то при этом возникает так называемое отношение подобия (IsA relationship) — расширение создает новый тип объектов, которые “подобны” исходному классу. Отношение подобия существенно отличается от отношения принадлежности  (HasA relationship), при котором один объект пользуется другим для хранения информации о своем состоянии или для выполнения своих функций — ему “принадлежит” ссылка на данный объект.

Давайте рассмотрим пример. Допустим, у нас имеется класс Point, представляющий точку в двумерном пространстве в виде пары координат (x, y). Класс Point можно расширить и

создать на его основе класс Pixel для представления цветного пикселя на экране. Pixel “подобен” Point; все, что справедливо по отношению к простой точке, будет справедливо и по отношению к пикселю. В класс Pixel можно включить механизм для хранения информации о цвете пикселя или ссылку на объект-экран, на котором находится пиксель. Пиксель “подобен” точке (то есть является ее частным случаем), так как он представляет собой точку на плоскости (экране) с расширенным контрактом (для него также определено понятие цвета и экрана).

С другой стороны, круг нельзя считать частным случаем точки. Хотя в принципе круг можно описать как точку, имеющую радиус, он обладает рядом свойств, которые отсутствуют у точки. Например, если у вас имеется метод, который помещает центр некоторого прямоугольника в заданной точке, то какой смысл будет иметь этот метод для круга? Каждому кругу “принадлежит” центр, который является точкой, но круг не является точкой с радиусом и не должен представляться в виде подкласса Point.

Правильный выбор иногда оказывается неочевидным — в зависимости от конкретного приложения могут применяться различные варианты. Единственное требование заключается в том, чтобы приложение работало, и притом осмысленно.

Налаживание связей подобия и принадлежности  — задача нетривиальная и чреватая осложнениями. Например, при использовании объектно-ориентированных средств для проектировании базы данных о работниках фирмы можно пойти по наиболее очевидному и общепринятому пути — создать класс Employee, в котором хранятся общие сведения для всех работников (например, имя и табельный номер) и затем расширить его для работы с определенными категориями работников — Manager, Engineer, FileClerk и т. д.

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

Более гибкий подход состоит в том, чтобы создать класс Role (функция работника) и расширить его для создания специализированных классов — например, Manager. В этом случае можно изменить класс Employee и превратить его в набор объектов Role. Тогда конкретное лицо может быть связано с постоянно изменяющимся набором функций внутри организации. От концепции “менеджер является работником” мы переходим к концепции “менеджер является функцией”, при которой работнику может принадлежать функция менеджера наряду с другими функциями.

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

Источник: Арнольд К., Гослинг Д. – Язык программирования Java (1997)

По теме:

  • Комментарии