Зависимость реализации от другого интерфейса

#inheritance #interface #dependencies #uml #class-diagram

Вопрос:

Рассмотрим эту UML-диаграмму (шаблона наблюдателя), взятую из обучающего видео YT:

введите описание изображения здесь

IObservable имеет зависимость от IObserver , потому что его методы принимают аргумент этого типа. Concrete* классы, конечно, реализуют свои соответствующие интерфейсы. И ConcreteObserver имеет зависимость от ConcreteObservable (и не IObservable , заметьте), поскольку он принимает это в качестве аргумента в своем конструкторе.

Что мне кажется неправильным, так это то, что ConcreteObservable необходимо реализовать IObservable методы, чтобы он также «использовал» IObserver напрямую. Разве не должна быть зависимость между теми, кто изображен на диаграмме, вот так?

введите описание изображения здесь

Я знаю, что это просто реализация IObservable методов и связь между ConcreteObservable ними IObserver косвенно показана другими стрелками на диаграмме, но, как я уже упоминал, мне это кажется неправильным, поскольку между ними существует прямая зависимость, и она не показана на диаграмме.

И просто для уточнения — я не говорю об этой конкретной диаграмме UML в частности — этот подход (с «отсутствующими» зависимостями), по-видимому, является нормой в большинстве/всех диаграммах UML с аналогичными отношениями классов. Это почему?

Ответ №1:

Почему?

Прежде всего, диаграмма не полностью соответствует описанию: диаграмма показывает ConcreteObservable , что является специализацией IObservable (т. Е. она наследует, а не просто реализует). То же ConcreteObserver самое для IObserver и.

Семантика UML довольно однозначна: если ConcreteObserver наследуется от IConcreteObserver , то он наследует не только свои публичные операции и свойства, но и свои отношения. Поэтому красная стрелка была бы излишней, поскольку она уже неявна. Более того, эта избыточность внесла бы двусмысленность: опытный читатель задался бы вопросом, является ли это той же самой или другой ассоциацией поверх существующей. В этом случае вам понадобятся дополнительные элементы для устранения неоднозначности (например, стрелка наследования между красной ассоциацией и исходной ассоциацией).

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

Привыкай к этому!

Но вместо того, чтобы добавлять ненужные элементы в диаграмму, используя расширенные функции UML для устранения неоднозначности и, таким образом, усложняя чтение диаграммы, я бы посоветовал привыкнуть к такому представлению: вы многое увидите в своей профессиональной жизни, и важно распознать «шаблон» (не обязательно шаблон наблюдателя здесь, но больше техники для разделения абстракций с использованием интерфейсов или обобщений/специализаций).

Комментарии:

1. Таким образом, такое поведение (подразумевающее зависимости) появляется только при реализации наследования и интерфейса? Во всех остальных случаях я должен явно нарисовать все зависимости?

2. @NPS да, без наследования и реализации неявных отношений нет, хотя моделистам разрешено показывать не все (например, если A связан с B, который связан с C, можно сделать вывод, что косвенно A связан с C. Вы можете показать это как производную ассоциацию, или вы можете решить не показывать такие косвенные ассоциации. Выбор за вами).