기본 콘텐츠로 건너뛰기

[UML]UML Tutorial

출처 프로페셔널 되기 | 힐줘볼까
원문 http://blog.naver.com/ugigi/70017700582
출처 : http://www.visualcase.com/tutorials/class-diagram.htm

3. The Class Diagram

클래스 다이어그램은 객체 지향 디자인에서 핵심이다. 시스템에서 객체들의 타입과 객체들의 정적인 관계를 기술한다.

Packages
패키지는 많은 수의 객체들을 관련된 그룹으로 구분할 수 있다. 많은 객체 지향 언어(자바와 같이), 패키지는 클래스와 인터페이스의 영역인 구분을 제공한다. UML에서 패키지 또한 유사하게 제공되지만 보다 폭넓은 목적으로 사용된다.



Visual Case에서 어떠한 UML 다이어그램도 패키지를 가질 수 있다. 각 패키지는 어떠한 형태이든 몇개이든 인터페이스와 클래스 같은 다른 UML 다이어그램을 담을 수 있다.

Classes
클래스 다이어그램의 핵심 엘리먼트는 클래스이다. 객체 지향 시스템에서, 클래스는 시스템내의 엔티티를 표현하든데 사용된다; 엔티티는 종종 실 세계의 객체들과 관계가 있다.



위의 Contact 클래스는 위치 정보를 담고 있는 간단한 클래스의 예제이다.

클래스는 세부분으로 나누어 진다:

Top : 클래스의 윗 부분에는 name, package, streotype이 들어간다. Visual Case에서 다이어그램에서 보여지는 클래스는 그들의 전체 경로 이름이를 가지고 보여지는 다이어그램으로서 동일한 패키지에 속할 수 없다. 선택적으로 클래스에 스트레오 타입을 할당할 수 있다.

Centre : 중간 부분은 클래스의 어트리뷰트를 담고 있다.

Bottom : 아래 부분은 클래스에서 수행될 수 있는 오퍼레이션이다.

Visual Case 클래스 다이어그램에서는 선택적으로 모든 클래스 또는 개별적인 클래스에서 어트리뷰트와 오퍼레이션 둘다 보여주거나 숨길 수 있다. 혼란스러운 정보만을 제공하는 여분의 정보를 가지고 있는 여러분의 구조를 강조하기를 원할 때 유용하다.

Attributes
어트리뷰트는 클래스의 프로퍼티이다. 위의 예에서, Contact는 주소, 도시, 지역, 나라, 우편번호를 담고 가지고 있다고 했다. 클래스를 구현할 때 어트리뷰트에 저장된 데이터를 추출하고 설정할 수 있는 기능은 일반적이다. 어트리뷰트 데이터를 설정하고 추출하는 메소드는 accessor 메소드 (또한 getting method, setting method)라고 불리고 여러분의 모델에서 사용되고 있다면 보여줄 필요는 없다.

어트리뷰트를 위한 포맷은 :
    visibility name: type = defaultValue

visibility는 다음과 같다 :
- Private
+ Public
# Protected
~ Package

객체 지향 디자인에서 대부분의 어트리뷰트를 private로 설정하고 accessor 메소드가 데이터를 제어하도록 하는 방법이 일반적이다. 예외적인 경우는 상수일 때 이다.

이름, visibility, 데이터 타입과 초기 값에 추가적으로 Visual Case는 다음의 프로퍼티를 지정할 수 있다:
Array : 어트리뷰트의 배열을 가지는 어트리뷰트로 설정할 수 있다 : 이름 옆에 [ ] 로 나타낸다.
Static : 클래스의 모든 인스턴스를 위해 오직 한번만 존재하는 정적인 어트리뷰트. 위의 예에서, city를 static으로 설정하면, Conta
           ct 클래스에서 언제든 사용될 수 있는 city 어트리뷰트는 항상 동일한 값을 가질 수 있다.
Final : 어트리뷰트가 final로 선언되면, 값은 변할 수 없다. 어트리뷰트는 상수이다.

Operations
클래스에 나타내는 오퍼레이션은 클래스의 데이터를 가지고 수행될 수 있는 함수 또는 작업을 나타낸다.


위의 List 클래스는 하나의 어트리뷰트와 세개의 오퍼레이션을 가지고 있다.

오퍼레이션의 포맷은 :
    visibility name (parameters) : type

이 포맷은 초기값이 제외되고 파라미터가 추가된 것을 제외하고는 어트리뷰트와 거의 유사하다.

파라미터는 다음의 포맷을 가지고 있다 :
    direction name: type = default value

direction은 in, out, inout 중의 하나일 수 있고 정의되지 않을 수도 있다.

Visual Case에서 다이어그램의 모든 클래스 또는 특정 클래스의 파라미터를 보여주거나 숨길 수 있다. 리스트가 히든이고 오퍼레이션이 파라미터를 가지고 있으면 숨겨지지는 않고 파라미터가 존재한다는 뜻으로 세개의 점(...)으로 나타난다. 때로는 오퍼레이션이 항상 보여줄 필요가 없는 많은 파라미터를 가지고 있다.

Generalization
generalization 링크는 하나의 클래스가 다른 클래스의 모든 어트리뷰트와 오퍼레이션과 함께 동작된다는 것을 보여주기 위해 두개의 클래스 사이에 사용된다, 하지만 어떤 방법으로 그들을 추가한다.



위의 다이어그램에서 Contact 클래스와 두개의 자식 클래스를 볼 수 있다. Client와 Company는 Contact를 inherit, generalize, 또는 extend 했다고 말할 수 있다. Client와 Company 에서 Contact의 모든 어트리뷰트(address, city, etc)가 존재하고 추가적인 정보가 더 있다. 위의 그림은 Contact는 Client와 Company의 수퍼클래스라고 부를 수 있다.

generalization 링크를 사용하면, 자식 클래스는 부모 클래스의 오퍼레이션을 오버라이드 할 수 있다. 이것은 수퍼클래스에 정의된 오퍼레이션을 포함할 수 있지만 새로운 오퍼레이션을 구현할 수 있다는 것이다.


위에서, OntraioTaxCalculator는 BasicTaxCalculator의 메소드를 재정의 또는 오버라이드한 것이다. 기본적으로, 코드는 다르지만 오퍼레이션은 동일한 방법으로 호출된다.

때로는 자식 클래스가 부모 클래스의 메소드를 오버라이드하길 원할 수도 있다. 이런 경우에 수퍼클래스에서 메소드를 abstract로 정의할 수 있다. 클래스가 추상 오퍼레이션을 가지고 있으면, 클래스 역시 추상 클래스로 간주된다. 추상 메소드와 클래스는 이탤릭체로 나타낸다. 추상 클래스의 모든 오퍼레이션이 추상 메소드일 필요는 없다.

AbstractTaxCalculator의 calculateTaxes 추상 오퍼레이션은 OntarioTaxCalculator와 NovaScotiaTaxCalculator 자식 클래스에서 반드시 구현되어야 한다. 오퍼레이션은 반드시 구현되어야 하기 때문에, 자식 클래스에서 보여줄 필요 없지만 보여줘도 된다. 핵심은 가능하면 여러분의 다이어그램을 명확하게 하라는 것이다. 위의 다이어그램은 간단하고 명확하다 하지만 상속 단계가 많고 많은 어트리뷰트와 많은 오퍼레이션이 있으면 오버라이드한 메소드 모두를 보여주길 원할 수 도 있다.

Interfaces
많은 객체지향 프로그래밍 언어에서 다중 상속을 지원하지 않는다. 인터페이스는 이러한 문제를 해결하기 위해 사용된다. 예를들어 앞의 Client와 Company 클래스 다이어그램에서 둘다 Contact를 generalize하지만 one or the other child classes may have something in common with a third class that we do not want to duplicate in multiple classes


위의 예제에 사용된 Sortable 인터페이스는 Company와 Product 모두 sort 오퍼레이션을 구현하는 것을 보여준다. Company와 Produc는 Sortable을 구현했다고 말할 수 있거나 Sortable이라고 말할 수 있다. Product가 이미 Contact를 generalize 했기 때문에 Sortable 또한 generalize할 수 없다. 대신에 Sortable을 인터페이스로 만들고 구현을 보여주기 위해서 realization 링크를 추가할 수 있다.

인터페이스는 어트리뷰를 가지지 않는다는 것을 제외하고는 추상 클래스와 아주 유사하다. 또한 클래스와는 다르게 인터페이스의 모든 오퍼레이션은 어떠한 구현도 가지지 않는다. Company와 Product 자식 클래스는 sort 오퍼레이션을 구현하도록 되어 있다.

Associations
클래스는 각각에 대한 참조를 가질 수 있다. Company 클래스는 Client 클래스를 참조하는 두개의 어트리뷰트를 가지고 있다.
 
비록 이것은 완벽하게 정확하다고 하더라도 association으로서 어트리뷰트를 보여주기 위해 때때로 보다 의미가 있다.

위의 두개의 association은 Contact 클래스의 구버전에서 어트리뷰트로서 동일한 의미를 가진다.

위의 association은 old contactPerson 어트리뷰트를 나타낸다. 하나의 Company에 하나의 contact person이 있다. The multiplicity of the association is one to one meaning that for every Companythere is one and only one contactPerson and for each contactPerson there is one Company. 아래쪽의 association에서는 각 company에 대해 0 또는 많은 employee가 있다. Multiplicities는 여러분이 정의하는대로 어떤것이든 될수 있다. 몇가지 예제를 보여준다:
    0        0
    1        하나
   1..*     하나 또는 그 이상
1..2, 10..*  하나 또는 둘 그리고 10 이상이고 3부터 9는 제외한다.
association의 끝 부부분의 화살표는 그들의 navigability를 나타낸다. 위의 예제에서, Company는 Client를 참조하지만 Client 클래스는 Company에 대해서 어떠한 것도 알지 못한다. 여러분의 association의 한쪽 또는 양쪽 또는 둘다 없이 navigability를 설정할 수 있다. navigability가 없다면 navigability가 정의되지 않았다는 것을 보여준다.

Aggregation and Composition


위의 예제는 aggregation association과 composition association을 보여준다.

composition association은 solid 다이어몬드로 나타난다. ProductGroup는 Product들로 구성된다. ProductGroup가 제거되면 group내의 Products또한 제거된다는 것을 뜻한다.

aggregation association은 hollow 다이어몬드로 나타난다. PurchaseOrder는 Products의 aggregate이다. PurchaseOrder가 제거되면 Product는 여전히 남는다.

composition과 aggreation 간의 차이점을 기억하기 힘들다면 알파벳을 생각하라. composition은 destory를 뜻하고 c의 다음 알파벳은 d라고 기억하면 된다.

Dependencies
dependency는 한쪽의 변화가 다른 쪽에 영향을 끼치는 두개의 엘리먼트 사이에 존재한다. 예를 들어, 한 클래스가 다른 클래스의 오퍼레이션을 호출하면 두 클래스 사이에 dependency가 존재하는 것이다. 오퍼레이션을 변경하면 dependent 클래스또한 변경될 것이다. 시스템을 설계할 때, dependencise를 최소화하는 것이 좋다.


설계에서 dependencies를 명확하게 하도록 하기 위해서 Package Diagram을 그리기를 원할 수도 있다. 패키지 다이어그램은 기본적으로 패키지와 dependencies를 보여주기 위한 클래스 다이어그램이다. dependencies는 UML의 어떠한 컴포넌트 간에도 존재할 수 있지만 가장 상위 레벨에서의 dependencies는 패키지 사이에 존재한다. 패키지 내에서 dependencies는 명세하기에 너무 많다. 많은 dependencies가 좋다는 것이 아니다. 패키지 내에서조차 dependencies를 제한하길 원한다, 하지만 특정한 패키지간에서는 존재하는 dependencies의 숫자를 제한하는 것이 좋다. 일반적으로, 적은 dependencies가 여러분의 시스템을 보다 scaleable하고 maintainable한 것이다.

Putting it all Together
클래스 다이어 그램은 정말 대부분의 객체 지향 설계에서 핵심이기 때문에 항상 사용하는 것이 좋다. 다행이도 클래스 다이어 그램은 대부분의 객체 지향 언어와 밀접히 관련이 있기 때문에 기본적인 부분(클래스, 오퍼레이션, 어트리뷰트, generalizations, 기타 등등)은 이해하기 쉽다. 알고 있는 부분부터 시작하면 된다.

설계에서 가장 중요한 부분은 자세한 부분에서 여러분을 혼란에 빠뜨리려는 것이 아니다. 많고 복잡한 다이어그램 보다는 몇개의 명확한 다이어그램이 훨씬 낫다. 앞에서 OntarioTaxCalculator와 NovaScotiaTaxCalculator에 의해 generalize된 AbstractTaxCalculator를 살펴 보았다. 열개의 캐나다 지방도 세개의 영토를 클래스 다이어그램으로 그리려고하면 상당히 복작해 질것이다. 미국의 세금 시스템을 설계하고 미국의 모든 주를 보여주려고하면 많은 문제가 있을 것이다. 보다 명확한 방법은 두개 혹은 세개의 자식 클래스만 명확하게 그린 후 다른 지방과 영토또한 동일한 방법으로 구현된다고 설명하는 것이 좋다.

설계를 심플하게 하면 보다 생산적이고 이해하기 쉽고 사용하기 쉬운 설계가 될 것 이다. 또한 시스템이 구현되고 업그레이드 됨에 따라 여러분의 구현에서 동기성을 유지하길 원할 것이다. 시스템의 핵심 개념이 심플한 설계라면 보다 쉬울 것이다.

댓글

이 블로그의 인기 게시물

80040154 오류로 인해 CLSID가 {xxxx-...}인 구성 요소의 COM 클래스 팩터리를 검색하지 못했습니다.

원문보기 .NET 으로 만든 응용프로그램에서 com 객체를 호출한 경우 Windows7 64bit 에서 제목과 같은 에러가 발생했다. Win32 COM 과 .NET 프로그램간의 호환성 때문에 생긴 문제였다. 원인은 .NET 실행시 JIT 컴파일러에 의해 최적화된 기계어로 변환되기 때문.. Win32 COM은 컴파일시.. Win32 COM에 맞춰 빌드 속성에서 하위버전으로 맞춰 컴파일을 다시하는 방법도 있지만 메인 프로젝트가 .NET이라면 참조되는 모든 프로젝트를 다 바꿔야할 노릇.. 또 다른 방법은 COM+를 이용하여 독립적으로 만드는 것이다. 분리시키는 방법은 아래 주소해서 확인할 수 있다. http://support.microsoft.com/kb/281335 나의 경우는 Win32 COM DLL을 64비트 .NET 프로그램에서 참조하니 COM 객체를 제대로 호출하지 못하였습니다. 그래서 .NET 프로그램의 Target Machine을 x86으로 설정하니 제대로 COM 객체를 호출하였습니다.

[Pyinstaller] 실행 파일 관리자 권한 획득하기

고객사에서 일부 사용자에게서 프로그램 오류가 발생한다며 아래와 같이 에러 캡처를 보내왔습니다. 프로그램에서 로그를 남기기 위해 로그 파일을 생성하는데 권한의 문제로 로그 파일을 생성하지 못해 프로그램 오류가 발생한 것 같습니다. 처음에는 Python 코드에서 관리자 권한을 요청하는 코드를 넣으려고 했는데, 실제로 Stackoverflow를 찾아보면 이런 내용이 나옵니다. 프로그램이 관리자 권한으로 실행되지 않았다면 관리자 권한으로 다시 프로그램을 실행시키는 코드입니다. import os import sys import win32com.shell.shell as shell ASADMIN = 'asadmin' if sys.argv[-1] != ASADMIN: script = os.path.abspath(sys.argv[0]) params = ' '.join([script] + sys.argv[1:] + [ASADMIN]) shell.ShellExecuteEx(lpVerb='runas', lpFile=sys.executable, lpParameters=params) sys.exit(0) 하지만 개인적으로 이런 방식은 마음에 들지 않았고 조금 더 찾아보니 Pyinstaller로 exe 파일을 만들 때 옵션을 설정하여 관리자 권한을 요청하도록 할 수 있다고 합니다. --uac-admin을 옵션에 추가하면 프로그램 실행 시 관리자 권한을 요청할 수 있습니다. pyinstaller.exe --uac-admin sample.py 하지만 안타깝게도 이 방식은 원하는 대로 동작하지 않았습니다. 마지막으로 manifest 파일을 이용하여 시도해보았습니다. spec 파일을 이용하여 pyinstaller로 빌드하면 <실행 파일 이름>.manifest 라는 파일이 생성됩니다. 파일에서 아랫부분을 찾아볼 수 있습니다. <security> <re

초간단 프로그램 락 걸기

프로그램에 락을 걸 일이 생겨났다. 하드웨어 락을 걸면 쉬울텐데 그 정도는 아니고 프로그램의 실행 날짜를 제한 해 달라고 한다. 그래서 파일(license.lic)을 가지고 락을 걸리고 결정을 했다. 요구 사항은 아래와 같다. 1. license.lic 파일이 없으면 프로그램을 실행 할수 없게 한다. 2. 지정한 날짜를 넘어서는 프로그램을 실행 할수 없게 한다. 3. 사용자가 시스템 날짜를 되돌렸을때 인식하여 프로그램을 실행 할수 없게 한다. 음.... 1.번 문제는 사용자가 프로그램을 실행하기 위해서 license.lic 파일을 받아야만 한다. license.lic 파일에는 최근 실행 날짜/종료날짜 이런식으로 적도록 한다.(물론 내용은 암호화 한다.) 최근 실행날짜는 프로그램이 실행때마다 업데이트 하도록 하고 시스템 날짜와 비교하여 시스템 날짜가 최근 실행 날짜보다 이전의 날짜면 시스템 날짜를 되돌렸다고 인식하도록 한다.(3.번 문제 해결) 시스템 날짜와 종료 날짜를 비교하여 시스템 날짜가 종료 날짜를 넘으면 프로그램을 실행 할수 없도록 한다.(2.번 문제 해결)