OpenU.Ru
Обозначает операцию, чью реализацию В программном коде (в виде метода или конечного
автомата, активизирующегося событием вызова) может предоставлять класс-потомок.
Операции, не являющиеся полиморфными, представляют собой листовые операции.
См. abstract operation; generalization;
inheritance; method.
Семантика
Если операция является полиморфной, то ее метод может быть предоставлен классом-потомком
(вне зависимости от того, предоставлен ли уже этот метод исходным классом или
нет). В противном случае метод операции должен определяться в том классе, который
ее объявлял, и переопределить его в классе-потомке нельзя. Метод является доступным,
если он был объявлен в текущем классе или унаследован от предка. Абстрактная
операция должна быть полиморфной (поскольку у нее нет прямой реализации). Если
операция объявлена листовой, то она не является полиморфной.
Если операция объявлена полиморфной в каком-либо классе (то есть если она не
объявлена листовой), ее можно объявить листовой в классе-потомке. Это не позволит
переопределить ее в следующих потомках. Листовую операцию нельзя объявлять полиморфной
в классе-потомке, так как ее нельзя переопределять.
UML не содержит правил комбинации методов для тех случаев, когда метод объявлен
в одном классе, а переопределен в другом (классе-потомке). Детали этих механизмов
можно обрабатывать с учетом специфики конкретного языка программирования, и
использовать для этого именованные значения. Такие действия, как явный вызов
унаследованного метода, в любом случае, зависят от языка.
Нотация
Не полиморфная операция объявляется при помощи ключевого слова {leaf}. В противном случае она считается полиморфной.
Обсуждение
Абстрактная операция обязательно является полиморфной, в противном случае ее
вообще было бы невозможно реализовать. Бертран Мейер (Bertrand Меуег) называет
такую операцию отложенной (deferred), так как ее спецификация дается в классе,
а реализация переносится в подклассы. Это один из наиболее важных (если не самый
важный) видов использования механизма наследования как в моделировании, так
и в программировании. С помощью наследования можно сделать так, чтобы операции
применялись к объектам, принадлежащих к различным классам. При этом источнику
вызова не обязательно знать или определять класс каждого объекта. Необходимо
лишь, чтобы все объекты имели единый класс-предок, в котором была определена
данная операция. Класс-предок не отвечает за реализацию операций - его задача
только определить их сигнатуры. Источник вызова может даже не иметь представления
о списке возможных подклассов. Из этого следует, что новые подклассы можно добавлять
и позже, не нарушая работы полиморфных операций. Исходный код при добавлении
новых подклассов не меняется. Возможность добавлять в программу новые подклассы
уже после написания изначального варианта кода - это одна из ключевых основ
объектно-ориентированных технологий.
Немного более проблематичной областью использования полиморфизма является замещение
(переопределение) метода, который был определен в классе, другим методом, который
определяется в подклассе. Это нередко принимают за некую разновидность совместного
использования кода, однако такой подход не безопасен. Переопределение не инкрементно,
поэтому для того, чтобы внести в метод даже небольшое изменение, в методе прямом
потомке должно быть повторено все содержимое исходного метода. Это может привести
к появлению ошибок. К тому же, если исходный метод впоследствии изменится, то
нет гарантий, что при этом изменения будут внесены и в метод-потомок. Существуют
моменты, когда подкласс может реализовывать операцию
абсолютно другим способом, однако многие разработчики предпочитают не использовать
механизм переопределения, так как он несет в себе больше опасностей, нежели
преимуществ. Вообще, методы должны быть либо целиком унаследованы без переопределения,
либо отложены. В последнем случае суперкласс не отвечает за реализацию операции
и при этом не возникает опасностей несовместимости.
Для того чтобы разрешить подклассу расширять реализацию операции, не теряя при
этом унаследованный метод, в большинстве языков программирования существует
форма комбинации методов. При этом используется тот метод, который был унаследован,
и разрешено внесение в него дополнительного кода. В языке C++, например, подход
не совсем соответствует объектно-ориентированным технологиям: наследуемый метод
должен быть явно вызван по имени класса к операции, что приводит к жесткому
встраиванию иерархии классов в программный код. В языке Smalltalk метод может
вызывать операцию с помощью ключевого слова super, при этом вызывается метод
класса-прямого предка. Такой механизм срабатывает и при изменении иерархии классов.
При этом возможно, при помощи ключевого слова super будет вызываться метод уже
из другого класса. Однако при использовании такой методики замещающий метод
всегда должен явно вызывать super. При этом очень часто появляются ошибки, так
как программисты забывают вставлять эти вызовы при возникновении изменений.
И, наконец, в языке CLOS существует очень общее и очень сложное множество правил
автоматического комбинирования методов, благодаря которым во время выполнения
одного вызова операции можно вызывать сразу несколько методов. Вся операция
реализуется в виде нескольких фрагментов, а не в виде цельного метода. Такой
способ является наиболее полным, однако, пользователю трудней работать с ним.
Язык UML не навязывает разработчику конкретный подход комбинации методов. Комбинация
методов представляет собой точку семантических вариаций, в которой можно выбирать
любой из вышеописанных подходов. Если в языке программирования не представлены
способы комбинирования методов, то инструмент моделирования может помочь создать
подходящий код на этом языке или же предупредить о возможных ошибках при использовании
переопределения метода.