Дж. Арлоу, А. Нейштадт - UML 2 и Унифицированный процесс - Практический объектно-ориентированный анализ и проектирование, страница 45
Описание файла
PDF-файл из архива "Дж. Арлоу, А. Нейштадт - UML 2 и Унифицированный процесс - Практический объектно-ориентированный анализ и проектирование", который расположен в категории "". Всё это находится в предмете "объектно-ориентированный анализ и проектирование" из 7 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Просмотр PDF-файла онлайн
Текст 45 страницы из PDF
10.2) кроется наследование между классами, посредством которого подклассы наследуют все возможности232Глава 10. Наследование и полиморфизмсвоих надклассов. Чтобы быть более специальными, подклассы наследуют:• атрибуты;• операции;• отношения;• ограничения.Подклассы наследуют характеристики своего суперкласса.Подклассы также могут вводить новые возможности и переопределятьоперации суперкласса. Все эти аспекты наследования подробно рассматриваются в следующих разделах.10.3.1.
ПереопределениеВ примере на рис. 10.3 подклассы Square и Circle класса Shape наследуютвсе его атрибуты, операции и ограничения. Это означает, что хотя мыи не видим этих элементов в подклассах, они присутствуют в них неявно. Говорят, что Square и Circle типа Shape.Обратите внимание, что операции draw() (отрисовать) и getArea() (найтиплощадь), определенные в Shape, не подходят для подклассов. Посылая сообщение draw(), мы ожидаем, что объект Square отрисует квадрат,а объект Circle – круг. Очевидно, что стандартная операция draw(), унаследованная обоими подклассами от их родителя, не годится. Фактически данная операция может вообще ничего не отрисовывать.
В конце концов, откуда ей знать, как должен выглядеть Shape? То же самоеможно сказать в отношении операции getArea(). Как вычислить площадь Shape?Shapeorigin : Point = (0,0)width : int {>0}height : int {>0}draw( g : Graphics )getArea() : intgetBoundingArea() : intSquareCircleradius: int = width/2{width = height}Рис.
10.3. Наследование характеристик суперкласса23310.3. Наследование классовЭти проблемы явно указывают на необходимость возможности изменения поведения суперкласса в подклассах. Классам Square и Circle надореализовать собственные операции draw() и getArea(), которые переопределяют стандартные операции, предоставляемые родителем, и обеспечивают более подходящее поведение.На рис. 10.4 все это показано в действии: подклассы Square и Circle предоставили собственные операции draw() и getArea(), имеющие соответствующее поведение.•Square::draw( g : Graphics ) – отрисовывает квадрат.•Square::getArea() : int – вычисляет и возвращает площадь квадрата.•Circle::draw( g : Graphics ) – отрисовывает круг.•Circle::getArea() : int – вычисляет и возвращает площадь круга.Подклассы переопределяют унаследованные операции, предоставляяновую операцию с такой же сигнатурой.Чтобы переопределить операцию надкласса, подкласс должен предоставить операцию с точно такой же сигнатурой, что и у переопределяемой операции надкласса.
UML определяет сигнатуру операции как имяоперации, ее возвращаемый тип и типы всех параметров в порядке перечисления. Имена параметров не учитываются, поскольку они являются просто удобным способом обращения к определенному параметрув теле операции и поэтому не считаются частью сигнатуры.Все это замечательно, но важно знать, что разные языки программирования могут поразному определять «сигнатуру операции».
Например, в C++ и Java возвращаемый тип операции не является частьюсигнатуры операции. Таким образом, если операции подкласса и надкласса будут отличаться только возвращаемым типом, в этих языкахбудет сформирована ошибка компилятора или интерпретатора.Shapedraw( g : Graphics )getArea() : intgetBoundingArea() : intширина высотаSquareCircledraw( g : Graphics )getArea() : intdraw( g : Graphics )getArea() : intРис.
10.4. Переопределение унаследованных операцийрадиус2234Глава 10. Наследование и полиморфизм10.3.2. Абстрактные операции и классыИногда требуется перенести реализацию операции в подклассы. В примере с классом Shape операция Shape::draw( g : Graphics ) – как раз такойслучай. В самом классе Shape обеспечить какуюлибо разумную реализацию этой операции невозможно, поскольку неизвестно, как должныотрисоваться «фигуры». Понятие «отрисовка фигуры» слишком абстрактное, чтобы иметь конкретную реализацию.У абстрактных операций нет реализации.Отсутствие реализации операции можно обозначить, сделав ее абстрактной операцией. В UML для этого имя операции просто записывается курсивом.Класс с одной или более абстрактными операциями является неполным, поскольку в нем есть операции, не имеющие реализации.
Этоозначает невозможность создания экземпляров подобных классов. Поэтому такие классы называют абстрактными. Чтобы показать, чтокласс является абстрактным, его имя записывается курсивом.Абстрактные классы имеют одну или более абстрактных операций. Создать экземпляр абстрактного класса невозможно.В примере на рис. 10.5 абстрактный класс Shape имеет две абстрактныеоперации: Shape::draw( g : Graphics ) и Shape::getArea() : int. Эти операцииреализуются подклассами Square и Circle. Хотя Shape является неполным, и его экземпляр не может быть создан, оба его подкласса предоставляют недостающие реализации, являются полными и могут иметьэкземпляры.
Любой класс, экземпляр которого может быть создан, называется конкретным классом.Операция getBoundingArea() является конкретной операцией класса Shape, потому что контактная площадь (bounding area) любой фигуры вычисляется одинаково: ширина фигуры умножается на высоту.Shapeабстрактныйклассабстрактныеоперацииdraw( g : Graphics )getArea() : intgetBoundingArea() : intконкретныеоперацииконкретныеклассыSquaredraw( g : Graphics )getArea() : intCircledraw( g : Graphics )getArea() : intРис. 10.5. Абстрактный класс Shape и конкретные подклассы Square и Circle23510.3.
Наследование классовИспользование абстрактных классов и операций обеспечивает двасерьезных преимущества:•В абстрактном суперклассе можно определять ряд абстрактныхопераций, которые должны быть реализованы всеми подклассамиShape. Это можно рассматривать как определение «контракта», который должны реализовать все конкретные подклассы Shape.•Можно написать код управления фигурами и затем подставить Circle, Square и другие подклассы Shape соответственно.
Согласно принципу замещаемости код, написанный для управления Shape, долженработать для всех подклассов Shape.Более подробно эти преимущества рассматриваются при обсужденииполиморфизма в разделе 10.4.10.3.3. Уровень абстракцииПеред тем как перейти к полиморфизму, неплохо было бы разобратьсяв уровнях абстракции. Что не так в модели на рис.
10.6?VehicleJaguarXJSTruckРис. 10.6. Пример неверной иерархииСущности, располагающиеся на одном уровне иерархии обобщения,должны находиться на одном уровне абстракции.Ответ: «в уровне абстракции». Иерархия обобщения определяет рядуровней абстракции, начиная от самого общего, находящегося на самом верху, вплоть до самого конкретного, находящегося в самом низуиерархии. Всегда необходимо стараться придерживаться одного уровня абстракции на одном уровне иерархии обобщения.
В приведенномвыше примере этого нет. JaguarXJS – марка автомобиля. Очевидно, чтоэто более низкий уровень абстракции, чем Truck (грузовик). Исправитьданную модель очень просто. Необходимо ввести между JaguarXJS и Vehicle (транспортное средство) суперкласс Car (автомобиль).10.3.4. Множественное наследованиеМножественное наследование – у класса может быть более одного непосредственного суперкласса.236Глава 10.
Наследование и полиморфизмUML позволяет классу иметь несколько непосредственных надклассов. Это называется множественным наследованием (multiple inherit+ance). Подкласс наследуется от всех его непосредственных надклассов.Обычно множественное наследование считают вопросом проектирования, поэтому отложим его обсуждение до раздела 17.6.2.10.4.
ПолиморфизмПолиморфизм означает «много форм». Полиморфная операция – этооперация, имеющая много реализаций. Мы уже видели две полиморфные операции в примере с классом Shape. Абстрактные операции draw()и getArea() класса Shape имеют две разные реализации: реализациюв классе Square и другую – в классе Circle. У этих операций «многоформ», следовательно, они полиморфны.Рисунок 10.7 прекрасно иллюстрирует полиморфизм.
Определен классShape, имеющий абстрактные операции draw() и getArea().Полиморфизм означает «много форм». Полиморфные операции имеютмного реализаций.Классы Square и Circle наследуются от Shape и предоставляют реализацииполиморфных операций Shape::draw() и Shape::getArea(). Все конкретныеподклассы Shape должны предоставлять конкретные операции draw()и getArea(), потому что в надклассе они являются абстрактными. Этозначит, что в draw() и getArea() все подклассы Shape можно интерпретировать (treat) одинаково.
Таким образом, набор абстрактных операцийявляется средством определения набора операций, которые должныбыть реализованы всеми конкретными подклассами. Это называютконтрактом.Конкретный подкласс должен реализовывать абстрактные операции,которые он наследует.Shapeабстрактныйсуперклассконкретныеподклассыполиморфныеоперацииdraw( g : Graphics )getArea() : intgetBoundingArea() : intSquaredraw( g : Graphics )getArea() : intCircledraw( g : Graphics )getArea() : intРис. 10.7. Иллюстрация полиморфизма23710.4. ПолиморфизмОчевидно, что реализация операций draw() и getArea() для классов Squareи Circle будет разной.