Открытая коллекция знаний

OpenU.Ru

Справочник UML. Объектно-ориентированное проектирование.

abstract (абстрактный)

Абстрактным может быть класс, вариант использования, сигнал, другой классификатор или элемент, который допускает обобщения и экземпляры которого нельзя создать непосредственно. Абстрактной может быть операция, у которой нет прямой реализации в программном коде.
Антоним: concrete.
См. abstract operation; generalizable element.

Семантика

Абстрактный класс - это класс, у которого нет непосредственных экземпляров, поскольку он имеет неполное описание (отсутствует метод для одной или нескольких операций) или, если описание класса является полным, явно указано отсутствие существования экземпляров. Абстрактный класс нуждается в уточнении. Иными словами, для того, чтобы им можно было пользоваться, у него должны быть потомки, имеющие реальные экземпляры. Абстрактный класс, являющийся листом, совершенно бесполезен (хотя он может присутствовать в каркасе, где подлежит уточнению при использовании каркаса). У конкретного класса не может быть абстрактных операций (иначе он был бы абстрактным). Абстрактный класс, напротив, вполне может иметь конкретные операции. Конкретными называются операции, которые могут быть реализованы в программном коде класса, затем использоваться во всех подклассах. В процессе реализации конкретных операций используются только атрибуты и операции, объявленные в данном классе. Одна из целей наследования - выделить такие операции в абстрактные суперклассы, после чего их могут наследовать все подклассы. Конкретные операции могут быть полиморфными (их будут переопределять методы классов-потомков), но это не обязательно. Класс, у которого реализованы все операции, может быть и абстрактным, однако при этом его абстрактность должна быть явно декларирована. Класс, у которого не реализована одна или более операций, автоматически считается абстрактным.
Такая же семантика абстрактности применима и к вариантам использования. Абстрактный вариант использования представляет собой фрагмент поведения, которое не может осуществиться само по себе, а должно быть более ясно определено в конкретных вариантах использования с помощью отношений обобщения, включения, или расширения. Когда общее поведение выделяется в абстрактный вариант использования, модель легче понять, потому что она становится меньше и проще.
Подобным образом дело обстоит и с другими абстрактными классификаторами и прочими элементами модели, допускающими обобщения.

Нотация

Имя абстрактного класса или абстрактной операции пишется курсивом. Кроме того, вы можете обозначить абстрактность элемента, поместив ключевое слово abstract в список свойств (под именем элемента или после него). Например, Account {abstract}.
См. class name.

Пример

На рис. 1 изображен абстрактный класс Account, у которого есть одна абстрактная операция (computeInterest) и одна конкретная (de-jusit). Абстрактный класс имеет два конкретных подкласса, которые реализуют операцию computeInterest. Атрибуты класса всегда конкретные.

Обсуждение

Разница между абстрактным и конкретным классом не так фундаментальна и четка, как может показаться на первый взгляд. Все зависит от конкретного разработчика модели. К тому же в процессе проектирования статус класса может меняться. Конкретный класс может стать абстрактным, если будет принято решение о разделении его возможностей и ответственностей по отдельным подклассам. Абстрактный класс станет конкретным, если его подклассы будут сочтены ненужными и убраны из модели или если вместо подклассов будут использованы значения атрибутов.
Самый простой способ сделать правильный выбор - придерживаться следующего правила: все нелистовые (non-leaf) классы считать абстрактными, а все листовые классы, соответственно, конкретными (исключение составляют абстрактные листовые классы, ожидающие дальнейшего уточнения). Это правило не относится непосредственно к языку UML, это стиль моделирования, который вы можете принимать или не принимать.
Правило "абстрактного суперкласса" основывается на том, что метод, реализующий операции в суперклассе, и метод, реализующий операции в конкретном классе, часто настолько разнятся, что могут не уместиться в рамках одного метода. В этом случае метод суперкласса вынужден делать следующее: во-первых, реализовать общее поведение, которое будут наследовать все классы-потомки; во-вторых, реализовать поведение для специфического класса. Часто эти две цели конфликтуют между собой.
Вместо этого любой неабстрактный суперкласс может быть преобразован в абстрактный суперкласс и конкретный подкласс. В таком случае абстрактный класс будет содержать в себе методы, наследуемые всеми подклассами, а конкретный подкласс - методы для специфического класса, допускающего наличие прямых экземпляров. Правило "абстрактного суперкласса" позволяет четко определять, какой тип данных может содержать переменная или параметр: экземпляры конкретного листового класса или экземпляры любого из подклассов суперкласса.
На рис. 2 изображен класс Letter (Письмо), который смоделировали вопреки правилу "абстрактного суперкласса". У класса Letter есть операция getNextSentence, которая возвращает текст следующего непрочитанного предложения, а также операция resetCursor, которая устанавливает курсор в начале текста. Подкласс Encrypted Letter (Шифрованное письмо) представляет собой письмо, которое было зашифровано. Операция getNextSentence в этом случае переопределяется, так как вначале требуется расшифровка текста. Реализация этой операции будет совершенно иной. Поскольку Letter - конкретный суперкласс, невозможно отличить переменную, которая должна содержать только экземпляры класса Letter (в котором операция getNextSentence не может быть переопределена) от переменной, которая может содержать как Letter, так и Encrypted Letter.


Изменив модель по правилу "абстрактного суперкласса", мы сделали ее симметричной (рис. 3). Теперь в ней есть абстрактный суперкласс Letter (которое может быть как обычным, так и зашифрованным). Кроме этого, появился новый класс - NonEncryptedLetter(Не-шифрованное письмо). Теперь getNextSentence является абстрактной операцией, которая реализуется каждым подклассом, a resetCursor - конкретной операцией, одинаковой для всех подклассов.
Если вы будете строить модель с учетом правила "абстрактного суперкласса", то можно не объявлять его абстрактным каждый раз, а делать это автоматически на основе классовой иерархии.
Как мы уже говорили, абстрактный листовой класс бесполезен, однако в этом правиле есть исключение. Речь идет о случае, когда абстрактный класс-лист служит общим пространством имен для глобальных (с областью действия в масштабе класса) атрибутов и операций, Впрочем, так поступают не очень часто - как правило, для удобства программистов, работающих с такими языками программирования, которые не поддерживают объектно-ориентированные технологии.
Мы же советуем избегать подобных случаев, так как они противоречат самому духу объектно-ориентированного проектирования, внося в модель глобальные зависимости. Ту же функциональность и большую открытость может обеспечить класс-одиночка. (См. раздел "Паттерн Singleton" в книге Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес. Приемы обьектно-ориентированного проектирования. Паттерны проектирования. Спб.: Питер, 2001. С. 131-138.)

Рис. 3. Абстрактный статус суперкласса помогает избежать неясности при моделировании
Рис. 3. Абстрактный статус суперкласса помогает избежать неясности при моделировании

Алфавитный указатель