2013-02-28 3 views
1

У меня возникает проблема при попытке проверить дубликаты в OCL.Поиск вложенных дубликатов в OCL

Вот упрощение диаграммы классов:

         +-----------+ 
             |ChapterName| 
             +-----------+ 
             ^0..* chapterNames 
              | 
             ^
              V 
       +-------+ books 0..* +----+ 
       |Catalog|<>------------>|Book| 
       +-------+    +----+ 
     catalogs 0..*^     ^0..* books 
        |      | 
        +----+ customers 0..* +--------+ 
        |Shop|<>-------------->|Customer| 
        +----+     +--------+ 

Атрибуты для каждого класса объявлены следующим образом:

  • ChapterName
    • Имя
  • Каталог
    • Категория

Проблема: То, что я хочу, чтобы проверить, если у клиента есть какие-нибудь книги с повторяющимися названиями глав, которые также принадлежат к определенной категории в каталоге.

Мне не удалось обвести вокруг себя логику. До сих пор я знаю:

context Shop 
self.customers.books->select(cubks | cubks = 
    self.catalogs.books->select(cabks | cabks = cubks)->first()) 

... Который должен найти книги из каталога, который имеет клиент.

Вопрос: Как я могу добавить дополнительные ограничения для решения проблемы выше?

Также. Я использую Eclipse, EMF и консоль OCL из Eclipse.

ответ

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(), которая возвращает все элементы из последовательности с удалением дубликатов. Тогда размер мешка равен размеру набора, если ни один элемент не был удален (т. Е. Если каждый элемент был уникальным).