Спецификация UML 2.5.1 гласит о владении на конце ассоциации:
- Обозначение через точку используется для обозначения принадлежности конца ассоциации, где точка показывает, что класс на другом конце линии владеет свойством, тип которого является классом, затронутым точкой.
И в нем говорится о навигации в конце ассоциации:
- Обозначение стрелки используется для обозначения возможности навигации в конце ассоциации. По определению все концы ассоциации, принадлежащие классу, доступны для навигации.
Я ясно понимаю, почему конец ассоциации, принадлежащий классу, доступен для навигации:
class A:
def __init__(self, b):
self.b = b # class-owned
class B:
pass
b = B()
a = A(b)
a.b # navigable
Однако у меня больше проблем с выяснением того, как можно перемещаться по концу ассоциации, принадлежащему ассоциации (то есть не принадлежащему классу)?
В спецификации указано, что ассоциации могут быть представлены классами ассоциаций:
AssociationClass можно рассматривать как ассоциацию, которая также имеет свойства класса, или как класс, который также имеет свойства ассоциации.
Поэтому я попытался реализовать ассоциацию с классом Python (как в SQL, где ассоциации часто реализуются с помощью таблиц ассоциаций SQL , когда концы ассоциации принадлежат ассоциации), но без особого успеха:
class A:
pass
class B:
pass
class A_B: # association class
def __init__(self, a, b):
self.a = a # association-owned
self.b = b # association-owned
b = B()
a = A()
a_b = A_B(a, b)
a.b # not navigable (AttributeError)
@qwerty_so Вы имеете в виду, что если конец ассоциации не принадлежит классу, то сама ассоциация принадлежит классу? Другими словами, всегда есть элемент, принадлежащий классу.
Ассоциация представляет собой связь между 2 или более классами. Роли представляют собой свойства классов, связанных через ассоциацию.
Ваш A_B не является ассоциацией. Это класс, который имеет ассоциации с A и B.
@qwerty_so Согласно спецификации UML, это класс ассоциации и, следовательно, ассоциация, поскольку она специализируется на ней: «Класс ассоциации можно рассматривать как ассоциацию, которая также имеет свойства класса, или как класс, который также имеет свойства ассоциации». Так что я не вижу ничего плохого в представлении ассоциаций с классами Python. В SQL люди делают то же самое, представляя ассоциации с таблицами ассоциаций SQL , когда концы ассоциации принадлежат ассоциации.
@qwerty_so Я только что опубликовал решение ниже. Спасибо за вашу помощь!
Решение состояло в том, чтобы установить ссылку ассоциации в качестве атрибута класса, как это было предложено @qwerty_so и этой статье:
class A:
def link(self, b):
self.a_b = A_B(self, b) # set attribute
class B:
pass
class A_B: # association class
def __init__(self, a, b):
self.a = a # association-owned
self.b = b # association-owned
b = B()
a = A()
a.link(b)
a.a_b.b # navigable
Я взял на себя смелость разместить ваш комментарий в ответе, где он должен быть.
@qwerty_so Спасибо, я переместил это в вопрос, потому что там это имеет больше смысла.
Моя причина заключалась в том, что ответы должны фактически отвечать на вопрос (что и сделала вставка). Ответ только по ссылке недействителен!
@qwerty_so Цитата из спецификации UML отвечает на ваш вопрос о природе класса Python A_B
: «Ваш A_B не является ассоциацией. Это класс, который имеет ассоциации с A и B». Это ассоциация (и даже без класса ассоциации UML, см. ответ Кристофа). Но это не отвечает на мой вопрос о том, как реализовать навигацию по концу ассоциации, принадлежащему ассоциации. Ответ состоял в том, чтобы сделать A_B
атрибутом A
в качестве ссылки, и вы предложили: «Потому что ассоциация привязана к обоим концам, а не висит в воздухе».
Не в этом дело. Ответ только по ссылке недействителен. Теперь я замечаю разницу в коде, но это не очевидно. Поэтому, пожалуйста, обобщите реальное решение в своем ответе, а не просто добавляйте ссылку, которая может исчезнуть через год (или меньше).
@qwerty_so Это уже то, что я сделал: «Решением было установить ссылку ассоциации как атрибут класса»,
Ну тогда оставь как есть. Для меня это не очень хороший ответ. Хорошего дня. (И, возможно, сравните это с объяснением Кристофа.)
В своем собственном ответе вы утверждаете, что A_B
- это класс ассоциации. Это действительно верная интерпретация.
Но не единственный:
Ассоциация объявляет, что могут быть связи между экземплярами, типы которых соответствуют или реализуют связанные типы. Ссылка — это кортеж с одним значением для каждого memberEnd ассоциации, где каждое значение — это экземпляр, тип которого соответствует типу на конце или реализует его. (раздел 11.5.3.1)
Ваш класс Python A_B
полностью соответствует этому определению: он реализует такую связь между связанными типами. На самом деле он предоставляет не что иное, как функциональность кортежа (в абстрактном смысле).
Классы вашей модели не обязательно связаны один к одному с вашими классами реализации. Моделирование означает принять точку зрения на мир. История слона и слепых говорит нам, что часто есть несколько действительных точек зрения. Таким образом, вы должны выбрать тот, который поможет вам лучше всего решить вашу проблему.
Дополнительное замечание: такие классы, как A_B
, часто используются для реализации ассоциаций «многие ко многим». Аналогичный выбор существует, когда задействованы тройные ассоциации: некоторые предпочитают рассматривать их как класс бинарных ассоциаций, имеющий ассоциацию с третьим классом. Некоторые предпочитают рассматривать его как простую N-арную ассоциацию. Оба, вероятно, будут реализованы с использованием класса A_B_C на языке реализации.
Вы имеете в виду, что мне даже не нужно было вводить более точное (специализированное) понятие класса ассоциации, я мог просто назвать его ассоциацией (например, 3 можно просто назвать числом, а не целым числом)? Или вы имеете в виду, что его также можно интерпретировать как не класс ассоциации?
@Maggyero второй: ваша модель имеет два класса A, B и связь между ними. Классы Python A и B реализуют классы A и B UML, а класс A_B Python реализует ассоциацию UML.
Хорошо. Класс A_B был бы необходим как класс ассоциации только в том случае, если бы он имел дополнительные свойства (помимо участников a и b), что здесь не так, поэтому возможны обе интерпретации?
@Магьеро Точно!
Потому что ассоциация привязана к любому концу, а не висит в воздухе.