Уточняя определения классов и операций, стараемся увеличить
степень наследуемости: чем больше классов находятся в отношении наследования,
тем меньше функций, реализующих операции этих классов необходимо будет
запрограммировать. Для увеличения степени наследуемости следует:
- Перестроить классы и операции.
- Выявить одинаковые (или взаимно однозначно соответствующие) операции и
атрибуты классов и определить для этих классов абстрактный суперкласс.
- Использовать делегирование операций, когда наследование семантически
некорректно.
Иногда одна и та же операция бывает определена в нескольких
классах, что позволяет ввести общий суперкласс для этих классов, в котором и
реализуется эта операция. Но чаще операции в разных классах бывают похожими, но
не одинаковыми. В таких случаях нужно попытаться внести несущественные изменения
в определения этих операций, чтобы они стали одинаковыми, т.е. имели одинаковый
интерфейс и семантику. При этом можно использовать следующие приемы:
- Если операции имеют одинаковую семантику, но разное число формальных
параметров, можно добавить отсутствующие параметры, но игнорировать их при
выполнении операции; например, операция отрисовки изображения на монохромный
монитор не требует параметра цвет, но его можно добавить и не принимать во
внимание при выполнении операции.
- Некоторые операции имеют меньше параметров потому, что они являются частными
случаями более общих операций; такие операции можно не реализовывать, сведя их к
более общим операциям с соответствующими значениями параметров; например,
добавление элемента в конец списка есть частный случай вставки элемента в
список.
- Одинаковые по смыслу атрибуты или операции разных классов могут иметь разные
имена; такие атрибуты (операции) можно переименовать и перенести в класс,
являющийся общим предком рассматриваемых классов.
- Операция может быть определена не во всех классах некоторой группы классов;
можно тем не менее вынести ее в их общий суперкласс, переопределив ее в
подклассах как пустую там, где она не нужна.
Использование делегирования операций можно пояснить на
следующем примере (рисунок 3.13). Класс стек близок классу список, причем
операциям стека push и pop соответствуют очевидные частные случаи
операций списка add и remove. Если реализовать класс стек как
подкласс класса список, то придется применять вместо операций push и
pop более общие операции add и remove, следя за их
параметрами, чтобы избежать записи или чтения из середины стека; это неудобно и
чревато ошибками. Гораздо лучше объявить класс список телом класса стек
(делегирование), обращаясь к операциям списка через операции стека. При этом, не
меняя класса список, мы заменяем его интерфейс интерфейсом класса стек.
Рис. 3.13. Реализация стека с использованием наследования(а) и
делегирования(б)
|