Objektsprache der Einschränkungen (und ein wenig über Metamodelle)

  • Tutorial
Bild

Unserer Meinung nach sollte die Object Constraint Language (OCL) jedem bekannt sein, der an der Modellierung beteiligt ist oder an einer modellorientierten Entwicklung interessiert ist. Im Allgemeinen wird ihm jedoch zu Unrecht die Aufmerksamkeit entzogen, und in der Tat ist der russischsprachige Informationssegment nur ein miserabler. Welche Sprache es ist und warum sie benötigt wird, wird in diesem Artikel beschrieben. Der Artikel gibt nicht vor, grundlegend, in Bezug auf Umfang, Richtigkeit der Definitionen usw. vollständig zu sein. Ihre Aufgabe: 1) Durch einfache Beispiele, um OCL denjenigen vorzustellen, die noch nie von dieser Sprache gehört haben, 2) und für diejenigen, die davon gehört haben, ist es möglich, neue Wege zu finden, sie zu benutzen.

Strukturelle und zusätzliche Einschränkungen


Beginnen wir gleich mit einem Beispiel. Angenommen, wir entwickeln ein Programm wie Jira, um Projekte und Aufgaben zu berücksichtigen und diese Aufgaben auf die Mitarbeiter zu verteilen. Das Datenmodell für ein solches Programm sieht möglicherweise sehr vereinfacht aus.

Bild

Nachdem wir ein solches Diagramm gezeichnet haben, haben wir unserem Themenbereich Beschränkungen auferlegt: Wir haben festgelegt, dass nur Mitarbeiter, Aufgaben und Projekte darin existieren können, dass sie genau solche Attribute besitzen, dass sie durch solche Verbindungen genau verbunden werden können. In unserem Fachgebiet muss ein Mitarbeiter beispielsweise einen vollständigen Namen und ein Geburtsdatum haben. Eine Aufgabe oder ein Projekt kann solche Attribute jedoch nicht haben. Oder der Ausführende einer Aufgabe kann nur ein Mitarbeiter sein, aber eine andere Aufgabe oder ein anderes Projekt kann kein Ausführender sein. Dies sind offensichtliche Dinge, aber es ist wichtig zu verstehen, dass wir beim Erstellen eines solchen Modells die Einschränkungen formulieren. Solche Einschränkungen werden manchmal als strukturelle Einschränkungen bezeichnet.

Häufig reichen strukturelle Einschränkungen beim Modellieren einer Domäne jedoch nicht aus. Beispielsweise kann eine Einschränkung erforderlich sein, dass der Projektmanager nicht gleichzeitig am Projekt teilnehmen kann. Diese Einschränkung folgt nun nicht aus diesem Diagramm. Wir geben andere Beispiele (mit einem Haken ;-)) für zusätzliche (nicht strukturelle) Einschränkungen:
  1. Der Auszubildende kann keine Projekte verwalten
  2. Ein Programmierer kann ein Projekt verwalten, aber nicht an anderen Projekten teilnehmen.
  3. Ein leitender Programmierer kann nicht mehr als zwei Projekte gleichzeitig verwalten
  4. Das Projekt sollte nur einen Leiter haben
  5. Vollständiger Namensvetter kann nicht an einem Projekt teilnehmen
  6. Ein geschlossenes Projekt kann keine offenen Aufgaben haben (eine Aufgabe wird als geschlossen betrachtet, wenn sie eine tatsächliche Ausführungszeit hat)
  7. Vor dem Zuweisen eines Ausführenden für die Aufgabe muss die geplante Ausführungszeit bestimmt werden
  8. Vor dem Schließen muss die geplante Ausführungszeit für die Aufgabe festgelegt werden.
  9. Ein Mitarbeiter in einem Projekt kann nur eine offene Aufgabe und nicht mehr als 5 Aufgaben für alle Projekte haben
  10. Der Mitarbeiter muss volljährig sein
  11. Der Name des Mitarbeiters sollte aus drei Teilen bestehen (Nachname, Vorname und Vorname), die durch Leerzeichen voneinander getrennt sind (Leerzeichen dürfen nicht doppelt, dreifach usw. sein).
  12. Leitender Programmierer kann Sigmund nicht anrufen
  13. Die tatsächliche Arbeitszeit für die Aufgabe darf die geplante Zeit nicht mehr als zweimal überschreiten
  14. Eine Aufgabe kann nicht ihre Unteraufgabe sein.
  15. Die geplante Zeit zum Abschließen der Aufgabe sollte nicht kürzer sein als die für die Unteraufgaben geplante Zeit
  16. ... selbst mit ein paar Einschränkungen aufwarten ...

Zusammenfassung In

verschiedenen Modellierungssprachen können Sie die strukturellen Einschränkungen des Themenbereichs beschreiben:
  • bei Objekttypen: Ein Objekt kann nur eine Instanz der entsprechenden Klasse sein (ein Mitarbeiter kann keine Projekteigenschaften haben, eine Aufgabe kann nicht in einer Tabelle mit Mitarbeitern gespeichert werden usw.);
  • akzeptable Eigenschaften und Assoziationen;
  • on types: Eigenschaften können nur Werte eines bestimmten Typs annehmen.
  • Multiplizität: Werte der gewünschten Eigenschaften / Assoziationen müssen angegeben werden, für Eigenschaften / Assoziationen mit mehreren "1" können nicht mehrere Werte angegeben werden, etc.

Zusätzliche Einschränkungen können mit zusätzlichen Sprachen wie OCL beschrieben werden.

Eclipse konfigurieren


Wenn Sie all dies in der Praxis ausprobieren möchten, ist Eclipse erforderlich. Wenn nicht, fahren Sie mit dem nächsten Abschnitt fort.
  1. Laden Sie Eclipse herunter und entpacken Sie es , vorzugsweise Eclipse Modeling Tools. Wenn Sie Rational Software Architect 9.0 (das auf Eclipse basiert) bereits verwenden, können Sie es verwenden.
  2. Installieren Sie die erforderlichen Bibliotheken:
    • Für Eclipse. Wählen Sie im Menü Hilfe -> Modellierungskomponenten installieren aus. Wählen Sie im angezeigten Fenster Folgendes aus: „Graphical Modeling Framework Tooling“, „OCL Tools“ und „Ecore Tools“ greifen nicht ineinander.
    • Für RSA 9.0. Kopieren Sie die Dateien org.eclipse.gmf.tooling.runtime _ *. Jar und org.eclipse.ocl.examples.interpreter _ *. Jar in den Ordner C: \ Programme \ IBM \ SDP \ plugins \ (je nach Installation der Ordner) vielleicht ein bisschen anders).
  3. Installieren Sie die pm * .jar- Plugins mit dem Test-Metamodell:
    • Für Eclipse. Kopieren Sie diese Dateien in den Ordner "$ ECLIPSE_HOME / dropins"
    • Für RSA 9.0. Kopieren Sie diese Dateien in den Ordner "C: \ Programme \ IBM \ SDP \ plugins \" (je nach Installation kann der Ordner leicht abweichen). Der Dropins-Ordner wird aufgrund einiger Fehler nicht empfohlen.
  4. Starten Sie Eclipse neu. Wählen Sie Datei -> Neu -> Andere ... aus dem Menü und schreiben Sie "pm" in die Suchleiste. "PM-Modell" und "PM-Diagramm" sollten angezeigt werden.
  5. Sie können entweder selbst ein Testmodell erstellen oder ein fertiges nehmen
  6. Öffnen Sie die Konsole: Fenster -> Ansicht anzeigen -> Andere ... Suchen Sie "Konsole" in der Liste.
  7. Öffnen Sie im Konsolenfenster die Dropdown-Liste "Open Console" und wählen Sie darin "Interactive OCL" (siehe Abbildung unten).
  8. Wählen Sie ein beliebiges Objekt im Diagramm aus und schreiben Sie "self" am unteren Rand der Konsole. Drücken Sie die Eingabetaste. Wenn alles richtig konfiguriert ist, sehen Sie so etwas:



Wenn das Plugin mit dem Metamodell für Sie nicht funktioniert, können Sie es selbst aus den Quellcodes kompilieren . Es verwendet eine relativ alte Version von GMF, um in RSA 9.0 zu arbeiten.

Beispiel Nr. 1. Die geplante Zeit für die Ausführung einer Aufgabe sollte nicht kürzer sein als die für Unteraufgaben geplante Zeit


Das Erste, was Sie über OCL wissen sollten, ist, dass eine Einschränkung immer für eine bestimmte Klasse von Objekten gilt. Bevor wir eine OCL-Regel schreiben, müssen wir diese Klasse auswählen. Manchmal ist diese Wahl nicht sehr offensichtlich, aber jetzt ist alles einfach: Die Regel gilt für die Aufgabe. Über die Self-Variable können wir auf eine bestimmte Instanz einer Aufgabe zugreifen. Wenn es notwendig ist, den Wert einer Eigenschaft der Aufgabe abzurufen, schreiben wir nach dem Variablennamen einen Punkt und dann den Namen dieser Eigenschaft. Ebenso können Sie den Namen der Assoziation angeben. Versuchen Sie es in Eclipse.

Hinweis

Um unnötige Probleme zu vermeiden, müssen im Modell alle Klassen, Eigenschaften usw. benannt mit lateinischen Zeichen. Sie können mithilfe der automatischen Vervollständigung (durch Drücken von Strg + LEERTASTE) genau herausfinden, wie diese oder jene Eigenschaft aufgerufen wird.

Die endgültige Kontrollregel ist in der Abbildung dargestellt.



Für OCL-Neulinge ist der Unterschied zwischen den Zeichen „.“ Und „->“ nicht so trivial.
Was nach dem Punkt kommt, bezieht sich auf jedes Element in der Sammlung von Werten oder Objekten.
Was nach dem Pfeil steht, gilt für die gesamte Sammlung von Werten oder Objekten.
Die Tabelle zeigt einige Beispiele für die Verwendung von Punkten und Pfeilen.
OCL-AusdruckInterpretieren eines OCL-Ausdrucks
self.plan_timeRuft den Wert der Eigenschaft "Plan_time" ab
Selbst. UnteraufgabenHolen Sie sich viele Unteraufgaben
Selbst. Unteraufgaben. time_planRufen Sie für jede Teilaufgabe in der Menge den Wert der Eigenschaft "Plan_time" ab und rufen Sie schließlich viele solcher Werte ab
self. subtasks. time_plan -> sum ()Berechnen Sie die Summe über den gesamten Wertesatz
self.time_plan -> sum ()Obwohl eine Aufgabe höchstens einen Wert für die Eigenschaft Plan_time haben kann, wird dieser Wert implizit in eine Menge (mit einem einzelnen Element) konvertiert. Die Operation sum () wird auf die Ergebnismenge angewendet.
Hinweis Eine Beschreibung der Operationen collect () und oclAsSet () finden

Sie in der OCL-Spezifikation .

Beispiel Nr. 2. Der Projektmanager sollte kein Teilnehmer am Projekt sein.


Die Abbildung zeigt mehrere äquivalente Formulierungen dieser Regel: Wir erhalten eine Liste der Projektteilnehmer und stellen sicher, dass es keinen Leiter darin gibt.



Die Selbstvariable kann weggelassen werden und ist implizit impliziert. Es ist jedoch wichtig zu beachten, dass einige Operationen (select, exists, forAll, ...) einen neuen Gültigkeitsbereich mit zusätzlichen impliziten Variablen (Iteratoren) erstellen. Gleichzeitig ist es ziemlich schwierig zu verstehen, zu welcher impliziten Variablen die Eigenschaftskette gehört. In solchen Situationen ist es sehr ratsam, alle Variablen (oder alle bis auf eine) explizit anzugeben.

Beispiel Nr. 3. Ein leitender Programmierer kann nicht mehr als zwei Projekte gleichzeitig verwalten


Anfänger, die solche Regeln schreiben, fragen in der Regel zuerst, ob in der OCL if-then-else. Ja, aber in den meisten Regeln ist es besser, stattdessen die Implikation zu verwenden.



Wenn die Prämisse der Implikation falsch ist, versuchen wir nicht einmal, den Rest der Bedingungen zu überprüfen. Wenn dies zutrifft, erhalten wir eine Liste der Projekte, die der Mitarbeiter verwaltet, schließen abgeschlossene Projekte aus und wenn die Anzahl solcher Projekte nicht mehr als zwei beträgt, glauben wir, dass die Bedingung erfüllt ist.

Beispiel Nr. 4. Vollständige Namensvetter können nicht an einem Projekt teilnehmen


Hier ist vielleicht die erste nicht-triviale Regel. Sie können versuchen, es ausgehend vom Mitarbeiter und vom Projekt zu formulieren. Es ist wichtig, mit der richtigen Klasse zu beginnen :-) Wenn Sie nichts über die Existenz der isUnique () -Operation wissen, können Sie monsteroide Konstruktionen einrahmen, die mir sehr ähnlich sind, als ich zum ersten Mal auf eine solche Aufgabe gestoßen bin.



Entfernen Sie die explizite Iterator-Deklaration aus der Regel (die "y" -Variable) und versuchen Sie, die Regel zu interpretieren. Persönlich kann ich mich nicht genau erinnern, was passieren wird. Es kann ein Fehler sein, dass nicht eindeutig festgestellt werden kann, welcher Name angesprochen wird. Oder vielleicht hat der Iterator Vorrang vor sich selbst. Müssen Sie sich die Spezifikation ansehen. In jedem Fall ist es ratsam, solche Situationen zu vermeiden und Variablen explizit anzugeben.

Hinweis

Iteratoren können mehrere sein. Schauen Sie sich die OCL-Spezifikation an und experimentieren Sie in der OCL-Konsole. Sehen Sie, wie die Spezifikation die Operation isUnique () definiert.

Beispiel Nr. 5. Ein Mitarbeiter in einem Projekt kann nur eine offene Aufgabe und nicht mehr als 5 Aufgaben für alle Projekte haben


In dieser Regel deklarieren wir zunächst eine Variable mit einer Liste offener Aufgaben. Dann überprüfen wir für sie zwei Bedingungen. Wir gehen davon aus, dass eine Aufgabe als offen gilt, wenn die tatsächliche Ausführungszeit dafür nicht angegeben ist.



Welche Klasse ist Ihrer Meinung nach am besten geeignet, um diese Regel zu definieren? Für einen Mitarbeiter oder eine Aufgabe?

Beispiel Nr. 6. Eine Aufgabe kann nicht ihre Unteraufgabe sein


Wenn Sie das Wesen der in der Abbildung dargestellten Regeln nicht sofort verstanden haben, ist dies ganz natürlich. Einerseits gibt es eine Klasse von Objekten "Task", andererseits hat die Task eine Zuordnung "Task", die die übergeordnete Task angibt. Es ist ratsam, Klassen und Eigenschaften / Assoziationen auf unterschiedliche Weise zu benennen. Dies verbessert die Qualität des Modells und vereinfacht das Verständnis der OCL-Regeln.



Beginnen wir mit der Implementierung der "Stirn" -Regel. Überprüfen wir, ob die Zuordnung "Problem" einer bestimmten Aufgabe die Aufgabe selbst anzeigt: "self. Task <> self". In der Abbildung haben wir den expliziten Verweis auf die Selbstvariable entfernt. Es scheint, dass dies nicht fatal ist, aber in OCL-Ausdrücken können wir uns nicht nur auf Eigenschaften oder Assoziationen beziehen, sondern auch auf Klassen. Mit diesem Ausdruck können wir beispielsweise eine Liste aller Tasks abrufen: "Task.allInstances ()". In diesem Beispiel entscheidet der OCL-Interpreter höchstwahrscheinlich, dass es sich um eine Task-Zuordnung handelt, nicht um eine Klasse. Ich wiederhole jedoch, es ist ratsam, solche Unklarheiten zu vermeiden.

Der zweite Nachteil dieser Regel besteht darin, dass nicht berücksichtigt wird, dass Unteraufgaben ihre eigenen Unteraufgaben haben können. Eine Aufgabe kann sich leicht als Teilaufgabe ihrer Teilaufgabe herausstellen. Um sicherzustellen, dass dies nicht der Fall ist, benötigen wir möglicherweise Schleifen oder rekursive Funktionen. In OCL gibt es jedoch keine Schleifen, und mit Funktionen ist nicht alles ganz einfach. Aber es gibt eine wunderbare Closure () Operation. Diese Operation ist für Sammlungen definiert, daher müssen Sie einen Pfeil davor und keinen Punkt setzen. Für jedes Element der Auflistung berechnet die closure () -Operation den als Argument angegebenen Ausdruck und kombiniert dann die erhaltenen Werte zu einer Auflistung. Für jedes Element, das diesen Ausdruck erneut auswertet, werden die erhaltenen Werte zur resultierenden Auflistung hinzugefügt, und so weiter:

self.Задача->union(self.Задача.Задача)->union(self.Задача.Задача.Задача)->union(...)

Die Abbildung zeigt zwei Versionen der Regel basierend auf der Rekursion für übergeordnete bzw. untergeordnete Aufgaben. Was ist Ihrer Meinung nach die beste Option (Trickfrage)?

Hinweis

Sicherlich werden Sie früher oder später Zyklen benötigen. In den meisten Fällen können Sie stattdessen die für Sammlungen definierten Vorgänge verwenden (select, exists, ...).

Wenn Sie noch eine Schleife benötigen, können Sie Folgendes ausprobieren:

Sequence{1..10}->collect(...)

Beachten Sie auch die Operation iterate ().

Beispiel Nr. 7. Der Name des Mitarbeiters sollte aus drei Teilen bestehen (Nachname, Vorname und Vorname), die durch Leerzeichen getrennt sind (Leerzeichen dürfen nicht doppelt, dreifach usw. sein).


Offensichtlich wäre eine solche Regel mit regulären Ausdrücken am einfachsten zu implementieren. Die OCL-Spezifikation enthält jedoch keine Operationen, mit denen Sie arbeiten können. In der Abbildung sehen Sie Beispiele für die Implementierung einer solchen Regel ohne die Verwendung regulärer Ausdrücke. Die gute Nachricht ist, dass die Standard-OCL-Bibliothek erweiterbar ist und in einigen Implementierungen die Operation matches () noch vorhanden ist, oder dass Sie sie selbst implementieren können.



OCL-Konstrukte


Alle von uns überprüften OCL-Ausdrücke sind in Basic OCL (Essential OCL) geschrieben. (Übrigens, wie denken Sie, unterscheiden sie sich?) Wir listen die Hauptkonstruktionen auf, die wir verwendet haben:
  • Selbstvariabel - Ein Ausdruck ist immer an eine bestimmte Klasse von Objekten gebunden
  • Auf Eigenschaften (und Verknüpfungen) über den Namen zugreifen:
    • self.Actor.Tasks.Project.Manager.Tasks ...
  • Arithmetische und logische Operationen
  • Funktionsaufruf:
    • Name.substring (1, 5)
    • Name.size () = Stringlänge
  • Mit Sammlungen arbeiten:
    • Name -> Größe () = 1, weil Der Mitarbeiter muss einen einzigen Namen haben
    • Aufgaben-> forAll (Aufgabe | Aufgabe. Zeitplan> 10)
  • Variablendeklaration:
    • let s1: Integer = name.indexOf ('') in
  • Bedingte Anweisung (if-then-else)

Complete OCL enthält einige zusätzliche Konstruktionen, die wir nicht im Detail betrachten werden. Sie können sich mit ihnen vertraut machen, indem Sie die Spezifikation lesen:
  • Nachrichten, Staaten
  • Pakete, Kontext, Ausdruckszweck (Paket, Kontext, Inv, Pre, Post, Body, Init, Ableiten)

Hausaufgaben


Siehe die OCL-Spezifikation .

Grundlegende Datentypen, Arten von Sammlungen (viele, Abfolgen usw.) verstehen. Warum gibt es Ihrer Meinung nach keine primitiven Typen für die Arbeit mit Datum und Uhrzeit in der OCL? Was ist, wenn Sie sie noch brauchen?

Verstehen Sie die Unterschiede zwischen Basic OCL, Essential OCL und Complete OCL.

Implementieren Sie andere OCL-Regeln selbst und überprüfen Sie sie in Eclipse.

Alle im Artikel angegebenen OCL-Ausdrücke können nur den Wert true oder false annehmen. (Stimmen Sie dieser Aussage im Übrigen zu?) Können OCL-Ausdrücke Ihrer Meinung nach einen numerischen Wertebereich haben, Zeichenfolgen, Wertesätze oder Objekte zurückgeben? Wie könnten solche nicht-booleschen OCL-Ausdrücke verwendet werden?

Kann das Ergebnis der Berechnung eines OCL-Ausdrucks Ihrer Meinung nach ein anderer OCL-Ausdruck sein?

Bonus Ein bisschen über Metamodelle


Wir haben zuvor lediglich die Einschränkungen unseres Modells beschrieben und diese Einschränkungen für bestimmte Mitarbeiter, Aufgaben und Projekte überprüft. Wir haben beispielsweise eine Regel beschrieben, nach der ein Projektmanager nicht gleichzeitig an einem Projekt teilnehmen kann. Darüber hinaus haben wir diese Regel für alle Projekte und Mitarbeiter im Allgemeinen beschrieben. Und dann haben sie es auf bestimmte Projekte und Mitarbeiter überprüft.

Beispiel Nr. 1. Metamodell "Mitarbeiter-Aufgaben-Gruppe"

Nun gehen wir eine Ebene höher. Zum Beispiel wollen wir eine andere Anwendung entwickeln - für einen Taxi-Bestellservice. Es wird ein ähnliches Datenmodell geben. Anstelle von Mitarbeitern soll es Fahrer geben, anstelle von Aufgaben - Aufträgen und anstelle von Projekten - Städte. Natürlich ist dies ein sehr bedingtes Beispiel, aber es wird nur benötigt, um die Idee zu demonstrieren. Oder sagen wir, wir müssen einen Antrag für einen Termin bei einem Arzt entwickeln. Es wird Ärzte, Abteilungen und Empfänge geben.

Wir können uns all diese Modelle ansehen und die allgemeinen Muster in ihnen sehen. Der Programmierer, der Fahrer und der Arzt sind im Wesentlichen dasselbe - nur ein Mitarbeiter. Bestellung, Empfang - das ist, wenn man es zusammenfasst, einfach eine Aufgabe. Fassen wir die Stadt, den Zweig und das Projekt zusammen. Wir nennen sie nur eine Gruppe. Die Verbindung zwischen dem Mitarbeiter und der Aufgabe wird als Ausführung bezeichnet. Die Verbindung zwischen dem Mitarbeiter und der Gruppe wird als Teilnahme bezeichnet.



Nachdem Sie und ich ein solches Bild gezeichnet haben, haben wir eine neue Ebene des Bewusstseins für den Themenbereich erreicht - wir haben ein Metamodell entwickelt, eine Sprache, in der wir jedes solche Modell beschreiben können.

Lassen Sie mich daran erinnern, dass das Modell, das wir im ersten Teil des Artikels erstellt haben, einige strukturelle und nicht strukturelle Einschränkungen für Informationen über Objekte in unserem Themenbereich auferlegt hat.

In ähnlicher Weise unterwirft ein Metamodell Modellen, die gemäß diesem Metamodell erstellt wurden, strukturelle und nicht strukturelle Einschränkungen. Beispielsweise kann es in jedem Modell, das diesem Metamodell entspricht, nur Elemente geben, die auf in der Abbildung rot markierten Metaklassen basieren. Beispielsweise kann die Klasse "Gebäude", "Straße" oder etwas Ähnliches, das kein Mitarbeiter, keine Aufgabe usw. ist, nicht im Modell angezeigt werden.

Hinweis

: Metamodelle basieren übrigens auf Metametamodellen (z. B. MOF, Ecore). Wenn Sie interessiert sind, lesen Sie die OMG MOF-Spezifikation . Im allgemeinen Fall kann es eine beliebige Anzahl von Simulationsstufen geben, in der Regel reichen jedoch 2-3 aus.

Übrigens, was denkst du, basierend auf welchem ​​Metametametamodell ist MOF selbst gebaut?

Wenn Sie keine Angst haben, Ihr Gehirn aus dem Gleichgewicht zu bringen , lesen Sie den Artikel Dragan Djuric, Dragan Gaševic und Vladan Devedžic „Das Tao der Modellierungsräume“.(Ich persönlich habe eine Störung des Gehirns von ihren Nachnamen). Bei der Entwicklung von Software ist im Großen und Ganzen alles ein Modell (von einem mentalen Bild im Kopf des Entwicklers bis hin zu Quellcode, Dokumentation, Testskripten usw.), und der Entwicklungsprozess besteht in der Konvertierung einiger Modelle in andere Modelle. Wir werden versuchen, das Thema der Modelltransformation in den folgenden Artikeln offenzulegen.

Entspricht das in der obigen Abbildung gezeigte Modell (grüne Rechtecke, blaue Linien) Ihrer Meinung nach Metamodellen (rote Rechtecke)?

Neben strukturellen Einschränkungen kann das Metamodell natürlich auch nichtstrukturelle Einschränkungen enthalten. Letzteres können wir in OCL noch einmal beschreiben. Beispiele für solche Regeln sind in der Abbildung dargestellt.



Hinweis

: Diese Zahl ist in der Tat nicht sehr korrekt. Anstelle eines vollwertigen Metamodells wird hier ein UML-Profil verwendet, das genau genommen ein gewöhnliches UML-Modell ist, das auf dem UML-Metamodell basiert (das wiederum auf dem MOF-Metamodell basiert). Tatsächlich werden Metamodelle jedoch häufig nicht von Grund auf neu erstellt, sondern in Form eines UML-Profils. Zum Beispiel wird in der Norm ISO 20022 ein Metamodell in zwei äquivalenten Versionen implementiert: 1) ein vollwertiges Metamodell basierend auf Ecore und 2) ein UML-Profil. Unter dem Gesichtspunkt der Ziele dieses Artikels sind diese Nuancen nicht sehr wichtig, daher betrachten wir das UML-Profil als „Metamodell“.

Beispiel Nr. 2. Metamodell "Entity-Attribute-Link"

Das oben beschriebene Metamodell sieht ein bisschen künstlich und wertlos aus. Versuchen wir, ein angemesseneres Metamodell zu erstellen. Angenommen, wir müssen eine Sprache entwickeln, mit der wir die Datenstruktur in einer relationalen Datenbank beschreiben können. In diesem Fall ist der Unterschied zwischen Teilnehmern, Aufgaben, Projekten usw. nicht so wichtig. All dies sind Entitäten, die Attribute haben können und die durch Beziehungen miteinander verbunden sind. In unserem Beispiel gibt es zwei Arten von Beziehungen: eine zu viele, viele zu viele. Die Metaklassen eines solchen Metamodells sind in der Figur durch rote Rechtecke beschrieben. Denken Sie, dass das in der Abbildung gezeigte Modell (grüne Rechtecke, blaue Linien) Metamodellen entspricht? Kann jedes Element dieses Modells zu einer der Metaklassen gehören?



Lassen Sie uns nun endlich mit dem Üben fortfahren. Hierfür verwende ich Rational Software Architect. Sie können jeden vernünftigen UML-Editor verwenden. Man könnte alles am Beispiel des freien und ideologisch korrekten Papyrus zeigen, aber leider ist es nicht sehr bequem.

Erstellen Sie daher im UML-Editor ein neues leeres Projekt. Erstellen Sie ein UML-Profil mit den folgenden Stereotypen.



Hinweis Beachten Sie

die Eigenschaften des Attribut-Stereotyps. Dies ist eine Liste von Eigenschaften, die jedes Attribut in unserem Modell besitzen kann.

Erstellen Sie dann das folgende UML-Modell, wenden Sie das soeben erstellte Profil darauf an und wenden Sie die erforderlichen Stereotypen an. Wenn Sie zu faul sind, um all dies zu erstellen, können Sie das fertige Projekt übernehmen .



Grob gesagt haben wir das Modell nach unserem „Metamodell“ gebaut. Jedes Element unseres Modells ist eine "Instanz" einer Metaklasse aus dem "Metamodell".

Примечание

Ещё раз повторюсь, что, строго говоря, это не так. И профиль, и стереотипы, и модель, и все элементы модели – всё что мы с вами создали – это экземпляры метаклассов из метамодели UML. Т.е. и профиль, и модель, которая его использует, находятся на одном уровне моделирования. Но с практической точки зрения, мы можем считать этот профиль «метамоделью», в соответствии с которым создана наша модель. Если вы понимаете о чём идет речь, то до понимая того что такое метамодели вам остается ещё один шаг – понять чем являются прямоугольники и линии на диаграммах, и понять чем является xmi-файл с точки зрения моделирования. В этом вам поможет статья, которая упоминалась выше.

Im Folgenden werden einige zusätzliche Einschränkungen unseres Metamodells in OCL beschrieben. Beispielsweise müssen Attribute zu Entitäten gehören. Wenn wir ein Metamodell in Form eines vollständigen Metamodells und kein Profil erstellen würden, würde diese Regel sehr einfach aussehen:

owner.oclIsKindOf(Entity)

Darüber hinaus müssten wir eine solche Regel nicht einmal beschreiben. Wir würden einfach eine Eigentümerzuordnung zwischen Attribut und Entität erstellen, die im Prinzip keine Elemente anderer Typen binden kann.

Da unser Metamodell jedoch als UML-Profil erstellt wurde, ist die Regel erforderlich und auf den ersten Blick nicht sehr trivial:

base_Property.class.getAppliedStereotype('PMProfile::Entity') <> null

Diese Regel gilt für das Attribut-Stereotyp, das die UML-Metaklasse "Property" erweitert. Dies bedeutet, dass wir im Modell eine Instanz des Attrbiute-Stereotyps an eine Eigenschaft (eine Instanz der UML-Metaklasse „Property“) binden können. In letzterem können wir bestimmte Werte für minLength, maxLength und pattern festlegen. Die OCL-Regel, die wir oben geschrieben haben, überprüft nur diese Instanz des Attribut-Stereotyps.

Über die Eigenschaft base_Property wechseln wir von der Instanz des Stereotyps zur Eigenschaft. Wechseln Sie dann über die Klassenvereinigung zu der Klasse, zu der die Eigenschaft gehört. Zuletzt prüfen wir, ob das Stereotyp „Entity“ auf diese Klasse angewendet wird.

Hinweis

Ich weiß nicht, inwieweit dies der Spezifikation entspricht, aber manchmal kann die Zuordnung zwischen einer Instanz eines Stereotyps und einer Instanz einer UML-Metaklasse (in diesem Fall base_Property) weggelassen werden. Sie wird implizit als self impliziert.

Hinweis

Wenn Sie eine Frage haben, wie ich herausgefunden habe, dass Sie die Klassenzuordnung verwenden müssen, dh auf zwei Arten: 1) automatische Vervollständigung in Eclipse (Strg + Leertaste) und 2) die OMG-UML-Spezifikation .

Die obige Regel verwendet den Standardtrick für Eclipse-basierte UML-Editoren. Die Operation getAppliedStereotype () ist jedoch eine nicht standardmäßige Erweiterung der OCL und wird in anderen Tools möglicherweise nicht unterstützt. Die gleiche Regel kann wie folgt geschrieben werden:

class.extension_Entity->notEmpty()

Wir prüfen, ob die Klasse, zu der die Eigenschaft gehört, eine Verbindung (über die extension_Entity-Zuordnung) mit der Erweiterung hat, die auf dem Entity-Stereotyp basiert.

Hinweis:

Theoretisch entspricht die zweite Option eher dem Standard. In älteren Versionen von Eclipse kann es jedoch zu Problemen kommen. Es wird empfohlen, die erste Option für diese Versionen zu verwenden.



Hinweis

Versuchen Sie, die Assoziationen base_Property, extension_Entity und class im Profil zu finden.

Die Abbildung zeigt drei weitere Regeln.
  1. Das Attribut muss einen Typ haben.
  2. In einer Eins-zu-Viele-Beziehung sollte die Multiplizität an einem Ende nicht mehr als 1 und am anderen Ende mehr als 1 sein.
  3. Alle Eigenschaften, die zu einer Entität gehören, müssen entweder reguläre Attribute oder Beziehungsrollen sein.

Glauben Sie, dass es möglich wäre, diese Regeln durch die üblichen strukturellen Einschränkungen zu ersetzen, wenn wir das Modell nicht als UML-Profil, sondern als auf MOF basierendes Metamodell erstellt hätten?

MOF und Ecore sind sich sehr ähnlich. Können Sie sich ein grundsätzlich anderes Metametamodell vorstellen?

Beispiele für Metamodellbeschränkungen

Im Folgenden finden Sie Beispiele für die einfachsten und komplexesten Regeln eines von uns erstellten realen Metamodells. Einerseits ist dies natürlich ein Beispiel für schrecklichen Code, andererseits eine Demonstration einiger OCL-Konstrukte :-) Die

maximale Wiederholbarkeit der ADT-Komponente sollte größer als 0 sein:

upper > 0

Die ADT-Komponente, die über die Abhängigkeitsbeziehung geerbt wird, muss sich an derselben Position befinden wie die entsprechende Komponente des übergeordneten Typs:

datatype.generalization->exists(
  getAppliedStereotype('SomeProfile::restriction') <> null)
implies (
let parent : DataType = datatype.general->any(true).oclAsType(DataType) in
let props : OrderedSet(Property) = parent.ownedAttribute->
  select(getAppliedStereotype('SomeProfile::Component') <> null) in
let cur : Property = props->select(x|x.type=self.type)->any(true) in
cur <> null implies (
let prevEnd : Integer = props->indexOf(cur) - 1 in
prevEnd = 0 or (
  let allPrev : OrderedSet(Property) = props->subOrderedSet(1, prevEnd) in
  let requiredPrev : OrderedSet(Property) = allPrev->select(lower > 0) in
  requiredPrev->isEmpty() or (
    let prevStart : Integer = allPrev->indexOf(requiredPrev->last()) in
    let allowedPrev : OrderedSet(Property) = allPrev->
      subOrderedSet(prevStart, allPrev->size()) in
    let index : Integer = datatype.ownedAttribute->
      indexOf(self.oclAsType(Property)) in
    index > 1 and (
      let selfAllPrev : OrderedSet(Property) = datatype.ownedAttribute->
        subOrderedSet(1, index - 1)->
        select(getAppliedStereotype('SomeProfile::Component') <> null) in
      selfAllPrev->isEmpty() or (
        let prevType : Type = selfAllPrev->last().type in
        allowedPrev->exists(x|x.type=prevType)))))))

Warum brauchen Sie OCL?


Die Kontrollregeln im Profil oder Metamodell - Sie wissen bereits alles darüber.

Kontrollregeln im Modell - und das auch.

Die Spezifikation von Operationen und berechneten Eigenschaften - Sie können dies selbst erfahren, indem Sie die OCL-Spezifikation lesen .

Modellkonvertierung ( QVT , MOF M2T ) - darüber werden wir in den folgenden Artikeln sprechen.

Erkennt die Bedeutung des Seins - meditiere dazu über die erste Zeichnung. Wo würdest du Jesus zeichnen? Und die Matrix?

Jetzt auch beliebt: