OCLとは何か?
OCLとは何か?
Object Constraint Languageの略。オブジェクト制約言語。
特徴
- ソフトウェアのモデルを記述するためのモデリング言語の1つである。
- UMLの追加機能(add-on)である。
- OCLの式(expression)は、UMLで定義された型を使用している。
- OCLで記述された式は、UMLなどでモデリングされた成果物に、不可欠な情報を追加することができる。
- OCLで追加する情報は、UMLの図だけでは表現することが不可能だったり、難しいものを含んでいる。
- UML1.xでは、OCLによって追加される情報は、制約(constraint)に限定されるべきだとされていたが、UML2.0は、次に示すものも、OCL式で記述するべきだとされている。
- 問い合わせ(クエリー)
- 値の参照
- 条件の指定
- モデル中のビジネスルールの指定
- 制約言語でもあり、問い合わせ言語でもある。
- OCLは、誰でも独自の構文を定義することができる。その条件は、言語構造へマップできるということ、ただ1つである。
- OCLは、Java, C#, Eiffelなどと同様に型付けされた言語である。したがって、型、構文レベルのチェックが可能であり、これにより、モデル中のエラーを検出し、取り除くことが容易である。
- OCLは、そのさまざまな特徴により、実装に依存することなく、モデルの意味するところを正確に記述することができる。これにより、UML/OCLモデルを『完全なPIM(プラットフォーム独立モデル)』にすることができる。
- OCLのすべての式のスーパークラスは、OclExpressionメタクラスである。
- 言語のメタモデル == 抽象構文(Abstruct Syntax)。言語はメタモデルによって定義される。
OCLとUMLで何ができるのか?
- 正しい(Good)なモデル
- 内容の充実(Solid)したモデル
- 矛盾のない(Consistent)モデル
- 首尾一貫(Coherent)したモデル
上のようなモデルを作り上げることができるため、MDAの本質である『モデルをソフトウェア開発の基礎とする』ということを、実現する方法として非常に有効である。
OCLはどんな目的で使用されるか?
- クエリー言語(問い合わせ)
- 不変式(invariant)
- 事前条件(pre condition)
- 事後条件(post condition)
- メッセージやアクションのターゲットを指定するため。
- 操作(operation)の制約を指定するため。
- 派生ルール(deriviation rule)を指定するため。
OCLを使うことのできる場所は?
OCLは、モデルの中のあらゆる場所で、値を示すために使用することができる。
値とは?
integerのような単純な値、オブジェクトや値の集まり、または、オブジェクトへの参照の集まりなど、さまざまなものが値となる可能性がある。
宣言型言語
OCLは、宣言型言語である。
つまり、「どのように」ではなく、「何が」なされるべきかということを表す。
これを確実なものにするため、OCLで記述されたいかなる式も、副作用を持つことは一切なく、システムの状態が、OCL式によって変わることはない。
キーワードと例
不変式(invariant)
context ContextName inv : self.attribute > 100
事前条件(pre)と事後条件(post)
context ContextName::operation():ReturnType pre : param01 > 100 post : result = 100
初期値(init)
context ContextName::Attribute init : 初期値
派生ルール(derive)
(属性などの場合)
context ContextName::Attribute derive : SuperClass.Feature.Attribute
(問い合わせ操作の場合)
これは、システムの状態を変えず、値や値の集合を返すだけのクエリー操作である。
コンテクストで、操作名、パラメータ、戻り値の型(シグニチャ)を記述する。
いっぽう、ボディには、この問い合わせ操作が何を行うかを記述することができる。
context ContextName::operation():ReturnType body : なにかしらの操作など() if さらに何かの操作 then 真の場合に実行される式 else 偽の場合に実行される式 endif
新たな属性や操作の定義(def)
定義する属性とその型を、defに続けて記述する。
context ContextName def : newAttribute : Integer = DeriveRule.member->getVal()
操作を定義する場合、その操作は常に問い合わせ操作である。
context ContextName def : getAttributeName():String = DeriveRule.getAttributeName()
変数の宣言(letキーワード)
let式は、あらゆる種類のOCL式に含まれる可能性がある。新しく定義された変数は、この特定の式の中だけで有効である。
変数は、キーワード、letに続けて変数名 : 変数の型 = 派生ルール、というように記述する。
context ContextName inv : let newAttribute : Boolean = self.feature.attribute01 and self.feature.attribute02 in if valid then newAttribute = false else newAttribute = true endif
OCL式のコンテクスト
不変条件の継承
- スーパークラスで定義されている不変条件は、サブクラスに継承される。
- サブクラスは、その不変条件を強めることは許されるが、スーパークラスでの定義を弱めることはできない。
- あるクラスのインスタンスが、期待されているすべての場所において、常にそのクラスのサブクラスのインスタンスを使うことができる。所謂、『リスコフ(Liskov)の置換原則』である。
- あるクラスで定義されている操作を、サブクラスが継承し、再定義する場合、サブクラスは、その操作の事前条件(pre condition)を弱くすることは許されるが、強くすることはできない。
- あるクラスで定義されている操作を、サブクラスが継承し、再定義する場合、サブクラスは、その操作の事後条件(post condition)を強くすることは許されるが、弱くすることはできない。
OCLの基本要素
これらは、UMLモデル要素を参照することなく利用することができる。
大きく分けると次の2種類。
- OCLの標準ライブラリで定義されている型
- 基本型(Integer、Real、String、Boolean)
- コレクション型(Collection、Bag、OrderedSet、Set、Sequence)
- ユーザ定義型(UMLモデルにおいて、ユーザに定義される型)
OCLのコメント
ハイフンを2つ書くと、それに続く同一行の内容はコメントとして扱われる。
context ContextName --このコンテクストでの不変条件を以下に示す。 inv : Attribute01 > 100
もしくは、スラッシュ+*、と、*+スラッシュで囲んだ範囲がコメントとして扱われる。
context ContextName /* このコンテクストでの不変条件を以下に示す。 Attributeは常に100よりも大きくなければならない。 */ inv : Attribute01 > 100
Boolean型と、その演算
演算 | 記法 | 戻り値の型 |
---|---|---|
or | a or b | Boolean |
and | a and b | Boolean |
exclusive or | a xor b | Boolean |
negation | not a | Boolean |
equals | a = b | Boolean |
not equals | a <> b | Boolean |
implies | a implies b | Boolean |
Boolean型の標準演算『implies演算』について
implies a implies b ※ a, bともにBoolean型 aがTrueのとき、bもTrueなら、式の結果もTrueとなる。 aがFalseであるとき、式の結果は、bの値にかかわらず、常にTrueと評価される。
Boolean型の if-then-else 演算
ifthen else endif これは、以下と同じ。 if (expression){ true case cord ; } else { false case cord ; }
Integer型とReal型の演算
演算 | 記法 | 戻り値の型 |
---|---|---|
equals | a = b | Boolean |
not equals | a <> b | Boolean |
less | a < b | Boolean |
more | a > b | Boolean |
less or equals | a <= b | Boolean |
more of equals | a >= b | Boolean |
plus | a + b | Integer or Real |
minus | a - b | Integer or Real |
multiplication | a * b | Integer or Real |
division | a / b | Real |
modulus | a.mod(b) | Integer |
integer division | a.div(b) | Integer |
absolute value | a.abs(b) | Integer or Real |
maximum | a.max(b) | Integer or Real |
minimum | a.min(b) | Integer or Real |
round(四捨五入) | a.round() | Integer |
floor(切り捨て) | a.floor() | Integer |
String型と演算
演算 | 記法 | 戻り値の型 |
---|---|---|
concatenation | string.concat(string) | String |
size | string.size() | Integer |
to lower case | string.toLower() | String |
to upper case | string.toUpper() | String |
substring | string.substring(int, int) | String |
equals | string01 = string02 | Boolean |
not equals | string01 <> string02 | Boolean |
UMLメタモデルの設計原則
UMLメタモデルの設計原則
- モジュール化(Modularity)
- 階層化(Layering)
- 区画化(Partitioning)
- 拡張性(Extensibility)
- 再利用性(Peuse)
- モジュール化(Modularity)
- 強疑集と疎結合の2つの原則により、構成要素をパッケージにグループ化し、特性をメタクラスに組織化する。
- 階層化(Layering)
- 2つの方法でUMLメタモデルに適用されている。
- パッケージは、メタ言語のコア構成要素を、それを使用する、より高いレベルの構成要素から分離するために階層化されている。
- 抽象化、特にインスタンス化を分離するために、4階層メタモデルアーキテクチャパターンが適用されている。
- 区画化(Partitioning)
- 同じ階層内において、概念による組織化をするために使用されている。インフラストラクチャライブラリの場合、現在、将来のメタモデリング標準に対応するため、きめ細かく区画されている。いっぽう、UMLの場合、パッケージ内の結合を強め、パッケージ缶の結合を緩めるため、区画化は荒削りである。
- 拡張性(Extensibility)
- UMLは、2通りの方法で拡張することができる。
Core(コア)
Core(コア)
- コアを特化/インポートするもの
- UML、MOF、CWM、Profilesなどは、コアを特化、もしくは、インポートしている。
- 再利用性
- コア・パッケージは、PrimitiveTypes、Abstractions、Basic、Constructsに再分割されている。このことによって、再利用することが、より容易になっている。
PABCの順番で覚えてみれば。ピーエービーシー
Package名 | 依存しているPackage数 | このPackageに依存しているPackage数 |
---|---|---|
PrimitiveTypes | 0 | 2 |
Abstractions | 1 | 2 |
Basic | 2 | 1 |
Constructs | 2 | 0 |