10.2 Абстрактные базовые классы

Предыдущая  Содержание  Следующая V*D*V

Если посмотреть на динамически компонуемые методы, соглашение об определённых именах методов в целях обратного вызова не выглядит ограничивающим. Метод, вызываемый для определённого объекта, то есть то, какой код выполняется для обратного вызова, зависит от объекта в дополнение к определённому имени метода.

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

 

% OrderedClass: Class OrderedArray: Object {

%-

    int cmp (const _self, int a, int b);

    void swap (_self, int a, int b);

%}

 

Алгоритм сортировки может использовать cmp() для сравнения двух элементов массива с помощью индексов и может использовать swap() для того, чтобы поменять их местами, если они не в должном порядке. Алгоритм сортировки может быть применён к любому подклассу OrderedArray, который реализует эти методы. Сам OrderedArray называется абстрактным базовым классом, потому что он служит только для декларации методов; этот класс не должен содержать объекты, если методы не определены.

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

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

Абстрактный базовый класс ограничивает архитектуру иерархии классов. Без множественного наследования клиент должен принадлежать только определённой части дерева класса, возглавляемого абстрактным базовым классом, независимо от его фактической роли в приложении. Для примера рассмотрим клиента окна, управляющего списком графических объектов. Изящное решение состоит в том, чтобы позволить клиенту принадлежать подклассу List, но реализация окна вынуждает клиент быть чем-то подобным WindowHandler. Как уже обсуждалось в разделе 4.9, можно создать агрегат и позволить клиенту содержать объект List, но тогда наша иерархия классов развивается согласно предписанию системы, а не согласно потребностям задач нашего приложения.

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

 

Предыдущая  Содержание  Следующая