我在尝试检查OCL中的重复项时遇到了挑战。
以下是类图的简化:
+-----------+
|ChapterName|
+-----------+
^ 0..* chapterNames
|
^
V
+-------+ books 0..* +----+
|Catalog|<>------------>|Book|
+-------+ +----+
catalogs 0..* ^ ^ 0..* books
| |
+----+ customers 0..* +--------+
|Shop|<>-------------->|Customer|
+----+ +--------+
每个类的属性声明如下:
问题: 我想检查的是客户是否有任何书籍的章节名称重复,这些书籍也属于目录中的特定类别。
我没有设法绕过逻辑。到目前为止我所拥有的是:
context Shop
self.customers.books->select(cubks | cubks =
self.catalogs.books->select(cabks | cabks = cubks)->first())
......哪个应该从目录中找到客户所拥有的书籍。
问题:如何添加更多限制来解决上述问题?
另外。我在Eclipse中使用Eclipse,EMF和OCL控制台。
答案 0 :(得分:1)
context Shop::checkForDuplicates(catalog:Catalog)
post: result =
self.customer.books->flatten()->select(book|
catalog.books->contains(book)
)->forEach(book|
chapterNames->asSet()->size()=chapterNames->size()
)
customer
是Set
; books
可以是Bag
或Set
(取决于是否允许重复的图书,我会假设它是Bag
,但这并不重要)。然后customer.books
是一袋书袋(每个顾客一袋),customer.books->flatten()
是客户拥有的所有书籍的一袋。
catalog.books
是Bag
或Set
(无关紧要)。 select
操作仅返回给定catalog
中包含的书籍(并且属于某些Customer
,因为我们从之前构建的包中进行选择)。
book.chapterNames
是一个Sequence
(我假设关联是有序的),其中包含该书中章节的名称。 forAll
为集合中的每个元素返回true
iff(即,对于给定目录中的每本书,由客户拥有),正文评估为true
。
现在的诀窍是依赖于操作Sequence::asSet()
,它返回序列中删除了重复项的所有元素。然后,如果没有元素被移除(即每个元素是唯一的),则袋的大小等于集合的大小。