Opierając się na podanych materiałach wykładowych, ten przewodnik obejmuje podstawowe pojęcia, składnię oraz zastosowania praktyczne języka ograniczeń obiektowych (OCL) w kontekście modelowania UML.

1. Wprowadzenie do OCL
Dlaczego potrzebujemy OCL?
Choć diagramy UML (takie jak diagramy klas) są doskonałe do wizualizacji struktury, nie mogą wyrażać wszystkich istotnych aspektów specyfikacji.
-
Język naturalny jest niejednoznaczny.
-
Tradycyjne języki formalne są jednoznaczne, ale zbyt trudne do odczytania i pisania dla przeciętnych modelistów systemów.
-
OCL mostkuje tę przerwę: jest to język formalny używany do wyrażania dokładnych ograniczeń, a mimo to przez cały czas pozostaje łatwy do odczytania i pisania.
Kluczowe cechy OCL
-
Czysty język wyrażeń: Wyrażenia nie mają skutków ubocznych. Ocena wyrażenia OCL zwraca wartość, ale nie może zmienić stan systemu. Może jednak opisać zmianę stanu (np. w warunku po).
-
Nie jest językiem programowania: Nie możesz pisać logiki programu, przepływu sterowania ani wywoływać procesów/operacji, które zmieniają stan.
-
Język typów: Każde wyrażenie ma typ. Poprawnie zapisane wyrażenia muszą spełniać zasady zgodności typów. Każdy klasifikator UML jest typem OCL.
-
Ocena natychmiastowa: Stan obiektów nie może się zmieniać podczas oceny wyrażenia OCL.
2. Podstawowa składnia i semantyka
Kontekst i self
Każdy wyrażenie OCL jest oceniane w kontekście określonego klasyfikatora UML (klasa, interfejs itp.).
-
kontekst: Określa klasę, do której stosuje się ograniczenie.
-
self: Słowo najważniejsze oznaczające konkretny egzemplarz klasy kontekstu, który jest oceniany.
Komentarze i operatory
-
Komentarze: Oznaczane przez -- (np. -- to jest komentarz).
-
Operatory infiksowe: Można używać standardowych operatorów matematycznych/logicznych (+, -, =, <). Koncepcyjnie, a + b jest identyczne z a.+(b).
Dostęp do adekwatności
Użyj notacji kropkowej, aby uzyskać dostęp do atrybutów lub operacji. Nawiasy są wymagane dla operacji, choćby jeżeli nie mają parametrów.
kontekst Osoba self.wiek -- Dostęp do atrybutu 'wiek' self.cenaAkcji() -- Wywołanie operacji 'cenaAkcji'3. Typy i kolekcje
Podstawowe zdefiniowane typy
OCL zawiera typy standardowe z określonymi operacjami:
-
Logiczny: prawda, fałsz (Operacje: i, lub, nie, oznacza, xor)
-
Liczba całkowita / Liczba rzeczywista: Liczby (Operacje: +, -, *, /, abs, maks, min, dzi, mod)
-
Ciąg: Tekst (Operacje: rozmiar, koniugacja, podciąg, naLiczbeCalkowita)
Zbiory
Zbiory to typy abstrakcyjne używane do przechowywania wielu elementów. Dostęp do nich uzyskuje się dzięki -> notacji.
-
Zbiór: Zbiór matematyczny (bez powtórzeń, nieuporządkowany). Zbiór {1, 2, 5}
-
UporządkowanyZbiór: Bez powtórzeń, ale uporządkowane według pozycji. UporządkowanyZbiór {5, 4, 3}
-
Pojemnik: Zezwala na duplikaty, nieuporządkowane. Pojemnik {1, 2, 2, 5}
-
Sequencja: Zezwala na duplikaty, uporządkowane. Sequencja {1, 2, 5, 10}
-
Uwaga: Zapis .. zapis tworzy sekwencję kolejnych liczb całkowitych: Sequencja {1..5}.
-
Kluczowe operacje na zbiorach
-
Wspólne: rozmiar(), jestPusty(), nieJestPusty(), zawiera(v), nieZawiera(v), liczba(v), suma().
-
Iteratory (kluczowe dla OCL):
-
wybierz(expr): Zwraca elementy, gdzie wyrażenie jest prawdziwe.
-
odrzuc(wyrażenie): Zwraca elementy, gdzie wyrażenie jest fałszywe.
-
zbierz(wyrażenie): Wyodrębnia określoną adekwatność ze wszystkich elementów do nowej kolekcji.
-
dlaWszystkich(wyrażenie): Zwraca prawda jeżeli wyrażenie jest prawdziwe dla wszystkich elementów.
-
istnieje(wyrażenie): Zwraca prawda jeżeli wyrażenie jest prawdziwe dla przynajmniej jednego elementu.
-
iteruj(elem; acc = init | wyrażenie): Ogólna podstawa dla wszystkich iteratorów.
-
Wariacje składni iteratora:
self.employee->select(wiek > 50) self.employee->select(p | p.wiek > 50) self.employee->select(p: Osoba | p.wiek > 50)4. Przechodzenie po modelach UML
OCL jest intensywnie wykorzystywany jako język nawigacji do przemieszczania się po powiązaniach.
Standardowa nawigacja
Nawiguj używając nazwy roli przeciwnej. Typ zwracany zależy od wielokrotności:
-
Wielokrotność 1 lub 0..1: Zwraca pojedynczy obiekt.
-
Wielokrotność *: Zwraca Zbiór (lub Uporządkowany zbiór jeżeli oznaczony {uporządkowany}).
Jeśli nazwa roli jest brakująca, użyj małej litery nazwy klasy po drugiej stronie (np. self.bank).
Klasy powiązań
Przejdź do klasy powiązania używając małej litery nazwy klasy powiązania.
kontekst Person self.job->size() >= 1 -- 'job' to klasa powiązania między Person i CompanyPowiązania rekurencyjne
Gdy powiązanie wraca do tej samej klasy (np. Małżeństwo między dwoma osobami), musisz określić kierunek dzięki nawiasów kwadratowych [nazwaRoli].
kontekst Osoba self.marszyna[żona]->select(m | m.zakończona = false)->size() = 1Zaawansowane powiązania
Użyj atrybutów jako wyróżnika w nawiasach kwadratowych, aby wybrać konkretny obiekt.
kontekst Bank self.klient[12345] -- Zwraca konkretną osobę z numerem konta 12345 self.klient -- Zwraca zbiór wszystkich klientówPrzypisywanie typu (rzutowanie)
Użyj oclAsType() aby uzyskać dostęp do adekwatności podtypu lub ukrytej adekwatności nadklasy.
self.oclAsType(Pod).p -- Dostęp do adekwatności 'p' zdefiniowanej w podtypie self.oclAsType(Nad).p -- Dostęp do adekwatności 'p' zdefiniowanej w nadklasie5. Pisanie ograniczeń
1. Inwarianty (inv)
Warunki, które muszą zawsze być prawdziwe dla wszystkich instancji klasy.
kontekst Firma inv: self.liczbaPracownikow <= 50 inv SME: self.cenaAkcyji() > 0 -- 'SME' to opcjonalna nazwa ograniczenia2. Warunki wstępne i końcowe (pre, post)
Ograniczenia związane z operacjami.
-
pre: Musi być prawdziwe przed wykonaniem.
-
post: Musi być prawdziwe po wykonanie. Użyj wynik dla wartości zwracanej.
-
@pre: Używane w warunkach po, aby odwołać się do wartości adekwatności przed rozpoczęcia operacji.
3. Wyrażenia ciała, początkowe i wyprowadzone
-
ciało: Definiuje wynik operacji zapytania (może być rekurencyjne).
-
init: Definiuje wartość początkową atrybutu.
-
wyprowadź: Definiuje atrybut wyprowadzony.
6. Zaawansowane cechy OCL
Wyrażenia let i def
-
let: Definiuje zmienną lokalną wewnątrz pojedynczego wyrażenia.
let sumaGodzin: Integer = self.pracujeNa->zbieraj(godziny)->suma() w sumaGodzin >= 30 -
def: Definiuje ponownie używane zmienne lub operacje przypisane do klasyfikatora.
def: maTytul(t: String): Logiczna = self.praca->istnieje(tytul = t)
Nieokreślone wartości (logika trójwartościowa)
Jeśli podwyrażenie jest nieokreślone (np. przeglądanie nullowego związku), całe wyrażenie jest nieokreślone. Jednak operatory logiczne mają wyjątki skrótu:
-
prawda lub <nieokreślone> = prawda
-
fałsz i <nieokreślone> = fałsz
-
fałsz implikuje <undefined> = prawda
-
<undefined> implikuje prawdę = prawda
Cechy klasy i zdefiniowane adekwatności obiektów
-
allInstances(): Zwraca zbiór wszystkich istniejących instancji klasy.
Person.allInstances()->size() <= 100 -
Właściwości obiektów: oclIsTypeOf(Typ), oclIsKindOf(Typ), oclInState(Stan), oclIsNew (używane w warunkach po).
7. Kompleksowy przykład badania: Model Firmy
Aby utwierdzić te koncepcje, przedstawiamy zestaw ograniczeń integralności stosowanych do modelu bazy danych Firmy (Pracownicy, Działy, Projekty, Zależni).

3 dni temu











