М. Фаулер, К. Скотт - UML Основы (1114905), страница 16
Текст из файла (страница 16)
В синтаксисе языка БМЕ зто выглядит следующим образом: <видимость> <имл>: <тип> = <значение по умолчанию), где видимость имеет такой же смысл, как и для операций, описываемых в следующем разделе. В чем же заключается различие между атрибутом и ассоциациейу С концептуальной точки зрения никакого различия нет.
Атрибут является еще одним видом нотации, который вы можете использовать, если сочтете это удобным. Атрибуты обычно имеют единственное значение. На диаграмме, как правило, не показывается, является ли атрибут обязательным или необязательным, хотя зто можно сделать, указав кратность в квадратных скобках после имени атрибута„например получениеДаннык( 0..11: Данные. Различие проявляется на уровнях спецификации и реализации. Атрибуты предполагают единственное направление навигации — от типа к атрибуту.
Кроме етого, подразумевается, что тип содержит только свою собственную копию атрибута объекта. В свою очередь, предполагают, что любой тип, используемый в качестве атрибута, обладает скорее значением, чем семантикой ссылки. Значения и ссылочные типы будут рассмотрены несколько позже. В данный момент атрибуты лучше всего представить себе как небольшие, простые классы, такие как строки, даты, денежные суммы и значения, не являющиеся объектами, например целое н вещественное.
Операции Операции представляют собой процессы, реализуемые некоторым классом. Существует очевидное соответствие между операциями и методами класса. На уровне спецификации операции соответствуют общедоступным методам над некоторым типом. Обычно можно не показывать такие операции, которые просто манипулируют атрибутами, поскольку они и так подразумеваются.
Однако иногда возникает необходимость показать, что данный атрибут предназначен только для чтения (геаб-оп)у) или является неизменным (Ггозеп), то есть его значение никогда не изменяется. В модели реализации можно также указать защищенные и закрытые операции. Полный синтаксис операций в языке ПМЕ выглядит следующим образом: <видимость> <имл> (<список-параметров>): .выражение-возвращающее-значение-типа> (<строка -свойств>) где видимость может принимать одно из трех значений: «+» общедоступная (рпЫ1с), ««»» защищенная (ргоСесСеб) или «-» закрытая (рг(чаСе). ° имя представляет собой строку символов.
Глава 4. Диаграммы клэссоз: основы ° список-параметров содержит разделенные запятой параметры, синтаксис которых аналогичен синтаксису атрибутов: <направление> <иия>: <тип> = <значение по умолчанию>. При этом дополнительным элементом является направление, которое применяется, чтобы показать характер использования параметра — для входа ((и), выхода (оиг) или в обоих направлениях ((поит). Если значение направления отсутствует, оно предполагается входным ((и).
° выражение-возвращающее-значение-типа содержит список разделенных запятой значений типов. Большинство разработчиков использует только один тип возвращаемого значения, но допускается использование и нескольких таких типов. ° строка-свойств указывает значения свойств, которые применяются к данной операции. Пример записи операции для счета клиента: + показатьСостояние (датаг Дата): Деньзи. В рамках концептуальной модели не следует использовать операции для спецификации интерфейса класса.
Вместо этого их следует использовать для представления принципиальных ответственностей класса, возможно, с помощью пары слов, выражающих ответственность в СКС-карточках (см. врезку в главе 5). По моему мнению, следует различать операции, изменяющие состояние класса, и операции, не делающие этого. Язык ПМБ определяет запрос как некую операцию, которая получает некоторое значение от класса, не изменяя при этом состояние системы, другими словами, не производя побочных эффектов.
Такую операцию можно пометить ограничением (запрос). Операции, которые изменяют состояние, я называю модификаторами. Полагаю, что запросы являются чрезвычайно полезными. Они могут выполняться в произвольном порядке, однако очень важно соблюдать последовательность выполнения модификаторов. В своей работе я избегаю значений, возвращаемых модификаторами, чтобы учесть указанное различие.
Другие термины, с которыми иногда приходится сталкиваться, — это методы извлечения значения (яе$Ыпя шеФЬобз) и методы установки значения (зеШпд ше1Ьобз). Метод извлечения значения возвращает некоторое значение из поля (и не делает ничего больше). Метод установки значения помещает некоторое значение в поле (и не делает ничего больше). За пределами класса клиент не способен определить, является ли запрос методом получения значения или является ли модификатор методом установки значений. Эта информация о методах является полностью внутренней для каждого из классов.
Существует еще одно различие между операцией и методом. Операция представляет собой вызов некоторой процедуры, в то время как метод является телом процедуры. Эти два понятия различают, когда имеют Обобщение дело с полиморфизмом. Если у вас есть супертип с тремя подтипами, каждый из которых переопределяет одну и ту же операцию супертипа, то вы имеете дело с одной операцией и четырьмя реализующими ее методами. Обычно термины «операция» и «метод» используются как взаимозаменяемые, однако бывают ситуации, когда полезно их различать. Иногда разработчики различают их, используя термины вызов метода или определение метода (для операции) и тело метода. В языках программирования на этот счет существуют свои собственные соглашения.
В языке С++ операции называются функциями-членами (шешЬег гппсйопэ), в то время как в языке Яша1На1Ы операции называются методами. В языке С++ используется также термин члены класса для обозначения операций и методов класса. В языке БМ) для указания атрибута илн операции применяется термин свойство ((еа$пге). Обобщение Типичный пример обобщения включает индивидуального и корпоративного клиентов некоторой бизнес-системы.
Они обладают некоторыми различиями. Однако, несмотря на различия, у них много общего. Одинаковые свойства можно поместить в общий класс Клиент (супертип), при этом класс Индивидуальный клиент и класс Корпоративный клиент будут выступать в качестве подтипов. Этот факт служит объектом разнообразных интерпретаций в моделях различных уровней. Например, на концептуальном уровне мы можем утверждать, что Корпоративный клиент является подтипом Клиента, если все экземпляры класса Корпоративный клиент по определению являются также экземплярами класса Клиент.
Таким образом, класс Корпоративный клиент является частной разновидностью класса Клиент. Основная идея заключается в следующем: все, что нам известно о классе Клиент (ассоциации, атрибуты, операции), справедливо также и для класса Корпоративный клиент. В модели уровня спецификации обобщение означает, что интерфейс подтипа должен включать все элементы интерфейса супертипа. Говорят, что интерфейс подтипа согласован с интерфейсом супертипа. Другая сторона обобщения связана с принципом замещения. Можно подставить класс Корпоративный клиент в любой код, где требуется класс Клиент, и при этом все должно работать прекрасно.
По существу, это означает, что если я написал код, предполагающий использование класса Клиент, то могу свободно использовать экземпляр любого подтипа класса Клиент. Класс Корпоративный клиент может реагировать на некоторые команды отличным от класса Клиент образом (используя полиморфизм), но это отличие не должно беспокоить вызывающий объект. 76 Глава 4. Диаграммы классов: основы С точки зрения реализации обобщение связано с понятием наследования в языках программирования.
Подкласс наследует все методы и поля суперкласса и может переопределять наследуемые методы. Ключевой особенностью здесь является различие между обобщением с точки зрения спецификации (подтипы или наследование интерфейса) и обобщением с точки зрения реализации (подклассы или наследование реализации). Подкласс представляет собой один из способов реализации подтипа. Подтип можно также реализовать с использованием механизма делегирования — действительно, многие образцы, описанные в книге Гамма и др., 1995 (20], содержат два класса с одинаковыми интерфейсами, но без использования подклассов. В книге Фаулера, 1997 (18] можно найти описание других идей реализации подтипов. Используя любую из этих форм реализации обобщения, вы всегда должны обеспечить справедливость этого обобщения на концептуальном уровне.