ナレッジNEW

【連載】概念モデリングを習得しよう:概念情報モデルをもとに、圏Iのモデルを現実世界と整合をとる(第17回)

【連載】概念モデリングを習得しよう:概念情報モデルをもとに、圏Iのモデルを現実世界と整合をとる(第17回)

【前回の連載記事はこちら】

【連載】概念モデリングを習得しよう:概念情報を使った現実世界の参照と更新(第16回)

読者の皆さん、こんにちは。Knowledge & Experience 代表の太田 寛です。この連載コラムでは概念モデリングの解説を行っています。
今回は、前回に続き果樹園を題材に、樹木の栽培、果実の成長、仲卸業者との契約といった現実の変化を、Shlaer-Mellor法に基づくアクション記述を用いて、圏Iのモデルにどのように反映・更新するかを解説します。

概念情報モデルをもとに、圏Iのモデルを現実世界と整合をとる

現実の世界に複数の樹木を栽培している果樹園があるとします。この様を概念情報モデルで参照するためには、まず、現実の状況と合致した圏Iのモデルが必要です。
また、栽培中の樹木にリンゴが生り始めたら、それに合わせて圏Iのモデルへの更新が生じます。
概念情報モデルをもとに、これらを実現するための、圏Iのモデルの作成、更新について説明します。

※説明文を簡略化するため、概念クラスは青のマーカー、概念インスタンス(単体、または集合)をアンダーライン付きの斜体で表現することにします

今、目の前に、10本の樹木を栽培している果樹園が一つあるとします。果樹園の名前は、“George Fluit Farm”とします。また、“OTA Company”という仲卸業者と、買取予定数が100個、1500円で買い取るという契約をしているとします。

まずは、果樹園を作るアクションを記述してみます。

アクション記述例 3.

1.  CREATE OBJECT INSTANCE 果樹園 OF OR ;
2.  果樹園.名前 = PARAM.果樹園名 ;

こちらも、BridgePoint の OAL を使って書いています。本来であれば、“CREATE CLASS INSTANCE …”なのですが、概念モデリングのベースである、Shlaer-Mellor 法の歴史に由来するものなので、我慢して、都度読み替えてください。

“George Fluit Farm”という名前は、このアクションを実行するときに供給する“PARAM.果樹園名”の値であるとします。また、記述例には、果樹園IDの値をセットするアクションがありませんが、1行目のアクションを実行したときに、圏Iのモデルに存在する果樹園の概念インスタンスの果樹園IDが全て異なるように、自動的に決まるものと思ってください。

次は、果樹園で栽培されている樹木を作るアクションです。

アクション記述例 4

1.  SELECT ANY 果樹園 FROM INSTANCE OF OR ;
2.    WHERE SELECTED.名前 == PARAM.果樹園名 ;
3.  CREATE OBJECT INSTANCE 樹木 OF FT ;
4.  RELATE 樹木 TO 果樹園 ACROSS R5 ;

ある樹木がどこの果樹園に植えられているか、逆から言えば、果樹園に植えられている樹木であるかは、概念情報モデルで記述された R5 をひな型にした意味的リンクを張ることと同義です。4行目は、R5をひな型にして、その意味的なリンクを作っています。

樹木は10本あるとしているので、圏Iのモデルを目の前の果樹園と同じにするために、このアクションを10回実行することになります。樹木IDは、果樹園の果樹園IDと同じように、作成時、全て異なる値がセットされると思ってください。

次は、仲買契約です。簡単にするため、契約を結ぶ仲卸業者に対応する概念インスタンスは、アクション記述例 3. と同様な形式で、既に作られているものとします。

アクション記述例 5.

1.  SELECT ANY 果樹園 FROM INSTANCE OF OR
2.    WHERE SELECTED.名前 == PARAM.果樹園名 ;
3.  SELECT ANY 仲卸業者 FROM INSTANCE OF MM
4.    WHERE SELECTED.名前 == PARAM.業者名 ;
5.  CREATE OBJECT INSTANCE 仲買契約 ;
6.  仲買契約.買取予定数 = PARAM.買取予定数 ;
7.  仲買契約.価格 = PARAM. 買取価格 ;
8.  RELATE 果樹園 TO 仲卸業者 ACROSS R6 USING 仲買契約 ;

概念情報モデル上では、仲買契約は、R6の関連クラスとして定義されています。果樹園仲卸業者の間にR6のリンクを作るときには、8行目のように、“USING ~”で、関連クラスをひな型とする概念インスタンスを指定します。

果樹園のそれぞれの樹木には、季節になると、花が咲き、受粉が行われて実がなります。その実は、概念情報モデルに従って判断すれば、“実”=“栽培中のリンゴ”です。実がなった段階で、栽培中のリンゴを圏Iのモデルに追加が必要だということになります。

ということで、栽培中のリンゴを一つ作って、R3 で果樹木にひも付けて…、おや?

ここで一つ問題が生じました。現行の概念情報モデルの樹木において、それぞれの果樹木の一意性を示す特徴値は、“樹木ID”と“果樹園ID”という特徴値の組しかありません。“樹木ID”は形式的にそれぞれの果樹木を区別するだけの値です。今のままでは、リンゴが生った樹木を指すことができません。そこで、アクションを記述する前に、概念情報モデルに、以下の修正を加えることにします(図表1)。

図表1: 修正された概念情報モデル

アクションの検討中に概念情報モデルの不具合を見つけることはよくあることです。
修正済みのモデルをもとに、栽培中のリンゴを一つ加えるアクションを示します。


アクション記述例 6.

1.  CREATE OBJECT INSTANCE リンゴ OF A ;
2.  CREATE OBJECT INSTANCE 栽培中のリンゴ OF AUC ;
3.  RELATE 栽培中のリンゴ TO リンゴ ACROSS R1 ;
4.  SELECT ANY 果樹園 FROM INSTANCE OF OR
5.    WHERE SELECTED.名前 == PARAM.果樹園名 ;
6.  SELECT ANY 樹木 RELATED BY 果樹園->FT[R5]
7.    WHERE SELECTED.樹木番号 == PARAM. 樹木番号 ;
8.  RELATE 栽培中のリンゴ TO 樹木 ACROSS R2;

リンゴ栽培中のリンゴの間に定義された R1 は、“is-a”のリレーションシップです。 “is-a”のリレーションシップは二項リレーションシップの特殊なケースなので、双方の概念インスタンスを作成して、他のリレーションシップと同じように“RELATE ~ TO ~”でひも付けます。

その後、日にちがたって、樹木ごとに収穫予定日が予測できたとします。その事実を圏Iのモデルに反映します。

アクション記述例 7.

1. SELECT ANY 果樹園 FROM INSTANCE OF OR
2.   WHERE SELECTED.名前 == PARAM.果樹園名 ;
3. SELECT ANY 樹木 RELATED BY 果樹園->FT[R5]
4.   WHERE SELECTED.樹木番号 == PARAM. 樹木番号 ;
5. 樹木.収穫予定日 = PARAM.収穫予定日 ;

さらに日にちがたつと、栽培中のリンゴはいい感じに成長して、収穫の時を迎えます。収穫された栽培中のリンゴは、収穫済みのリンゴになります。収穫は、収穫予定日を過ぎた樹木の全ての栽培中のリンゴを一気に行うこととします。

この様を、概念情報モデルに則って、アクションを記述します。


アクション記述例 8.

1.  SELECT ANY 果樹園 FROM INSTANCES OF OR
2.    WHERE SELECTED.名前 == PARAM.果樹園名 ;
3.  SELECT MANY 収穫対象の果樹木の集合 RELATED BY 果樹園->FT[R5]
4.    WHERE SELECTED.収穫予定日 <= TIM::current_date() ;
5.  FOR EACH 果樹木 IN 収穫対象の果樹木の集合
6.    SELECT MANY 栽培中のリンゴの集合 RELATED BY 果樹木->AUC[R2] ;
7.    FOR EACH 栽培中のリンゴ IN 栽培中のリンゴの集合
8.      SELECT ONE リンゴ RELATED BY 栽培中のリンゴ->A[R1] ;
9.      UNRELATE リンゴ FROM 栽培中のリンゴ ACROSS R1 ;
10.     UNRELATE 栽培中のリンゴ FROM 果樹木 ACROSS R2 ;
11.     DELETE OBJECT INSTANCE 栽培中のリンゴ ;
12.     CREATE OBJECT INSTANCE 収穫済みのリンゴ OF PHA ;
13.     RELATE 収穫済みのリンゴ TO リンゴ ACROSS R1 ;
14.     RELATE 収穫済みのリンゴ TO 果樹木 ACROSS R3 ;
15.     収穫済みのリンゴ.収穫日 = TIM::current_date() ;
16.     収穫済みのリンゴ.重さ = リンゴ.measure_weight() ;
17.   END FOR;
18.  END FOR ;

幾つか新しい種類のアクション・プロセスが出てきました。

5~18行目と、8~17行目で使われている“FOR EACH instance IN instanceSet ~ END FOR ;”ですが、instanceSet に格納された概念インスタンスの集合の要素それぞれに対して、“~” を実行することを表します。5行目と18行目の下位のアクション群には、3行目で収集された、果樹園で栽培している(R5)樹木のうち、収穫対象の樹木の集合の要素それぞれがデータフローとして供給されるという意味です。

8~14行目では、

  • “UNRELATE instanceA FROM instanceB ACROSS Rn
  • “DELETE OBJECT INSTANCE instance

が使われています。

前者は、二つの概念インスタンス(instanceAinstanceB)の間に張られていた意味的リンクを切ることを意味します。概念情報モデルによっては、二つの概念インスタンスの間に複数の意味的リンクが張られていることがあるので、どの意味的リンクを切るのかを、Rn で明示します。

後者は、概念インスタンス(instance)を削除するというプロセスです。現実世界の事柄が消えれば、その写しである圏Iのモデルの対応する要素は消えなければなりません。

存在していた概念インスタンスを削除する際には、概念情報モデルで記述された制約を満たすため、対象の概念インスタンスに張られている意味的リンクは全て削除しなければなりません。

例に出てくるSELECTに続いて、“ANY”、“MANY”、“ONE”の3種類が続きます。それぞれ、概念インスタンスを選択する際、

  • ANY

    FROM の場合、指定された概念クラスをひな型とする概念インスタンス群から(条件に合致する)任意の一つだけを選択する

    RELATED BY の場合、指定されたリレーションシップの多重度が、“*”、もしくは“1..*”の場合、ひも付いた概念インスタンス群の中から(条件に合致した)任意の一つだけを選択する

  • MANY

    FROM の場合、指定された概念クラスをひな型とする概念インスタンス群から(条件に合致する)全てを選択する

    RELATED BY の場合、指定されたリレーションシップの多重度が、“*”、もしくは“1..*”の場合、ひも付いた概念インスタンス群の中から(条件に合致した)全てを選する

  • ONE

    RELATED BY で指定されたリレーションシップの多重度が、“1”、もしくは“0..1”の場合に使用可能

という決まりになっています。

8~14行目の一連のアクションは、概念モデリングになじみのない読者には珍紛漢紛のことと思うので、詳述しておくことにします。

栽培中のリンゴは、そもそもリンゴなので、R1でつながったただ一つのリンゴとつながっています。このリンゴは、樹木に生っている・もぎ取られたに関係なく、存在する物理的な一つのリンゴに一対一対応しています。栽培中のリンゴが収穫されるということは、栽培中のリンゴがなくなって、収穫済みのリンゴができあがることを意味します。“栽培中のリンゴがなくなる”とは、概念モデリング的には、R1の意味的リンクが切れることと、栽培中のリンゴという概念インスタンスが消えるということを意味します。この一連の流れが、9、11行目のアクションです。

また、栽培中のリンゴとR1でつながっていたリンゴが収穫済みになるので、新たに一つ収穫済みのリンゴを作成して、そのリンゴとR1の意味的つながりを張ります。それが、12、13行目のアクションです。

さらに、栽培中のリンゴはR2で、収穫済みのリンゴは、R3で樹木とのリレーションシップを持っています。10行目で栽培中のリンゴを削除する前に樹木との意味的リンクを切り、14行目で収穫済みのリンゴの意味的リンクを張ることにより、概念情報モデルの制約を満たします。

16行目では、“リンゴ.measure_weight()”というプロセスが使われています。これは、ある収穫済みのリンゴの重量を量って、果物重量という単位のデータを取得するというアクションです。モデル作成者の胸の内に立ち入ってみると、「対象としている概念ドメインにおいては、リンゴの重さがただ単に知りたいだけ」と考えていて、「重ささえ判れば、その重さをどんな方法で測ろうと別段構わない」とも考えています。このように考えることが、“概念ドメイン”ごとに概念モデルを作成するときの基本的な立場です。

しかし、圏Iのモデルに対する参照・更新を明確に記述するためには、このような HOW はどうでもいいけれども、何らかの明記が必要なケースが出てしまいます。このケースでは、重さはリンゴにひも付くものなので、便宜的にリンゴにひも付けた“measure_weight”という名前のプロセスとして宣言することにしています。このようなプロセスを概念クラスの“オペレーション(Operation)”と呼ぶことにしています。一般的なオブジェクト指向プログラミングにおける、instance method と類似の概念と考えて差し支えありません。

4、15行目には、“TIM::current_date()” というプロセスが使われています。ぱっと見、“今日の日付は?”というデータフローを出力するものであると想像が付くものと思われます。こちらも、“measure_weight”と同様、モデル化対象の概念ドメインにおいては、単に日付を知りたいだけであって、日付をどのように知るかを問題にはしていません。ただし、“measure_weight”とは異なり、意味的にひも付けるのが妥当な概念クラスは、概念情報モデルには宣言されていません。日付や時間に関わる概念は、“果樹園”という概念ドメインにおいては、どこでも使われる可能性があるからです。そのため、日付や時間に関わるデータを供給する“TIM(Timeの略)”という項目を別途用意して、そのオペレーションとして必要なプロセスを宣言することにします。この“TIM”のような項目を、概念モデリングでは、“外部実体(External Entity)”と呼んでいます。外部実体は、モデル化対象の概念ドメインとは意味的論理空間が異なります。外部実体は概念クラスではないので、概念クラスとの間に一切のリレーションシップは定義できません。

以上で、更新で使われる基本的なプロセスが全て出そろいました。

次回は、複数のドメインファンクションが同時に動作する際の課題を踏まえ、状態モデルによる動的振舞いの記述方法について解説します。

SNSシェア

この記事は面白かったですか?

今後の改善の参考にさせていただきます!

Search Articles By The Cast出演者/執筆者から記事を探す

Search Articless By The Categoryカテゴリから記事を探す

Ranking

ランキング

もっと見る