본문 바로가기

프로그래밍

OCL(The Object Constraint Language) 예제를 기반으로한 설명

OCL?

 OCL은 1995년 IBM에서 Insurance division에 대한 비지니스 모델을 작성하기 위해서 개발되었고 UML version 1.1에 추가가 되었습니다. UML은 객체들에 대한 관계를 표현할 수 있지만 제약사항에 대한 표현의 한계를 지니고 있습니다. 

예를 들어서 Mortgage(대출)에 startDate와 endDate가 있는데 startDate는 항상 endDate보다 빨라야 한다는 제약사항을 UML에서는 표현할 수 없습니다. 이러한 문제를 해결하기 위해서 개발된 것이 OCL입니다. OCL은 Object Oriented System에 제약사항을 추가하는 역할로 생각하시면 됩니다. 

 


OCL을 사용하는 부분

class와 type의 invariant
메소드의 pre- 와 post- condition
operation에 대한 제약
요구사항과 명세

 


OCL Example

A Mortgage System

대출 시스템에 대한 UML Class Diagram 입니다. 

여기서 두 개의 제약사항을 추가해보겠습니다. 

 

1. Person은 자신이 소유하고 있는 집에 대해서만 Mortgage(대출)을 빌릴 수 있다. 

2. startDate는 endDate보다 빨라야 한다. 

 

이 제약사항을 OCL 언어로 바꾼다면 다음과 같이 기술할 수 있습니다. 

 

1. 

context Mortgage

invariant: self.security.owner = self.borrower

2. 

context Mortgage

invariant: self.startDage < self.endDate

 

1번은 "Mortgage객체에 대한 security(House)의 소유자와 Mortgage객체에 대한 borrower(Person)이 같다" 입니다. 

2번은 "Mortgage객체에 대한 startDate 는 endDate보다 작다" 입니다. 

 

self는 객체 자기자신을 명시적으로 나타내기 위해서 사용되며 생략이 가능합니다. 

따라서 위의 OCL은 다음과 같이 기술할 수 있습니다.  

1*.

context Mortgage

invariant: security.owner = borrower

2*. 

context Mortgage

invariant: startDage < endDate

 

여기서 하나를 더 추가해보겠습니다. 

3.대출이 된 집의 value는 0보다 커야 한다. 

context Mortgage

invariant valuerestriction: self.security.Money > 0

 

여기서 valuerestriction은 해당 invariant에 대한 설명을 나타냅니다. 


Invariants using Navigation

context 객체가 아닌, context와 association을 하고 있는 객체에 대한 설명과 제약사항을 나타내기 위해서 화살표를 사용합니다. 

context CustomerCard
invariant printedName: printedName = owner.title.concat(‘ ‘).concat(owner.name)

printedName -> a String.
owner -> a Customer instance.
owner.title -> a String.
owner.name -> a String.

CustomerCard 객체와 연관된 owner 객체에 대한  설명이 있습니다.
* String은 OCL에서 정의된 Type 입니다. 

* concat(String) : String 또한 OCL에서 정의된 method입니다. 

 

Collection을 다루기 전에 쉬었다 갑시다..

 


Collection Type

multiplicity 가 1보다 큰 경우 Navigation의 association에서 역할은 Collection type이 됩니다. 

Collection에 대한 operation은 'Collection -> op_name' 를 통해서 접근할 수 있습니다. 

UML에서 Customer는 여러 종류의 Membership을 가질 수 있습니다. 

context Customer
membership     

 

Operations)

<collection> -> size()
  isEmpty()
  notEmpty()
  sum()
  count(object)
  includes(object)
  includesAll(collection)

 

types)

set no duplicates
Bag duplicates allowed
Bag을 Set으로 바꾸기 위해서는 
Bag -> asSet Naviation을 추가 
Sequence ordered Bad

 

여기서 membership은 Collection 타입으로 Memebership 객체의 집합을 나타냅니다. 

The partners of a loyalty program have at least one delivered service The number of a customer’s programs is equal to that of his/her valid cards

context LoyaltyProgram
invariant minServices:
partners.deliveredservices->size() >= 1

context Customer
invariant sizesAgree:
Programs->size() = cards->select(valid=true)->size()

 

includeAll)

 

아래 두 개는 고객의 멤버십카드가 고객의 카드라는 제약사항을 나타냅니다.

The cards of the Memberships of a customer are only the customer’s cards

The owner of the card of a Membership must be the customer in the membership

context Customer
invariant correctCard: 
cards->includesAll (Membership.card)

context Membership
invariant correctCard: card.owner = customer

* 두 개 중에 더 나은 것은 Membership을 context로 잡은 2번째입니다. 

* includesAll 부분은 "Customer의 카드는 ( )안에의 카드를 모두 포함해야 한다"를 나타냅니다. 

* Membership.card는 고객의 모든 멥버십의 카드이므로 collection입니다. 

 

includes)

includes는 collection type에 대한 operation입니다. 
괄호 안에 있는 것을 포함해야 합니다. 

A customer card belongs only to a Membership of its owner

context CustomerCard
invariant correctCard:
owner.Membership -> includes (membership)

owner -> a Customer instance.
owner.Membership -> a set of Membership instances.
membership -> a Membership instance of CustommerCard

* membership은 customer card의 멤버십이므로 하나만 존재합니다. 


More operations)

 

<b.e.> : boolean expression

<v.e.> : values    expression

<collection> -> select (e : T | <b.e>)
  reject (e : T| <b.e>)
  collect (e : T| <v.e.>)
  forAll (e : T* | <b.e.>)
  exists (e: T| <b.e.>)
  iterate(e:T1; r:T2 = <v.e.> | <v.e.>

아래 두 개는 동일한 제약사항을 나타냅니다. 

고객의 카드의 이름에 고객의 이름이 붙는다. 

context StoreCard
invariant: printName = owner.title.concat(owner.name)




context Customer
cards -> forAll (
          printName = owner.title.concat(owner.name) )

고객의 모든 카드의 이름을 설정한다. 

 


UML example

Modules can be taken iff they have more than seven students registered

context Module
invariant: taken_by -> size() >7

The assessments for a module must total 100%

context Module
invariant: set_work->sum() =100

Students must register for 120 credits each year

context Student
invariant: takes.credit->sum() = 120

Students must take at least 90 credits of CS modules each year

context Student
invariant: takes->select(code.substring(1,2)='CS')->sum()>=90

All modules must have at least one assessment worth over 50%

context Module
invariant: set_work->exits(weight>50)

Students can only have assessments for modules which they are taking

context Student
invariant: takes->includeAll(submits.for_module)