객체지향 분석설계2 (소프트웨어 공학)



UML

무엇이든지 복잡한 생각이나 아이디어를 간결하고 정확하게 표현하려면 여러 방법이 있지만 이를 통해서 의사소통의 오류를 줄이는 것은 소프트웨어 개발 프로젝트에선 필수사항이다. 정확한 의사소통은 먼저 표현하는 의미를 잘 정의해야 하고 대상을 표현하는 데 적합하고 모든 이해당사자가 이해하기 쉬워야 한다. 그래서 표준이나 규격이 필요한 것이고 이것이 객체지향에서는 UML(Unified Modeling Language)을 사용하는 것이다.

UML은 OMT(Object Modeling Technique)와 Booch, OOSE(Obect Oriented Software Engineering)의 통합으로 만들어진 표현 방법으로 객체지향 분석설계기법으로 매우 유용하고 시스템 개발에선 크게 기능적 모형, 객체 모형 및 동적 모형으로 구성된다. 이 중 중요한 다이어그램이 5가지 있는데 Use Case, Class, Sequence, State, Activity가 그것이다.

  • Use Case Diagram
    : 시스템의 기능적인 측면을 모델링하는 데 사용되고 주로 사용자와 시스템 간의 상호작용을 보여준다. 액터(Actor)는 시스템과 상호작용하는 주체(사용자 또는 외부 시스템)를 나타내며 유스케이스(Use Case)는 시스템이 수행하는 기능을 나타낸다.
  • Class Diagram
    : 시스템의 정적인 구조를 모델링하는 데 사용되며 클래스, 인터페이스, 연관 관계, 상속 관계 등을 시각적으로 표현한다. 클래스 다이어그램은 소프트웨어의 구조를 이해하고 객체 간의 관계를 잘 파악할 수 있다.
  • Sequence Diagram
    : 시스템의 동적인 동작을 시간의 흐름에 따라 나타내며 객체 간의 메시지 교환을 보여주고 객체 간의 상호작용과 시간 순서를 시각화하여 효과적으로 커뮤니케이션 흐름을 이해할 수 있게 한다.
  • State Diagram
    : 객체의 생명주기와 상태 변화를 모델링하는 데 사용되며 주로 객체의 상태가 어떻게 변화하고 이벤트에 응답하는지를 시각적으로 보여준다. 상태 다이어그램은 복잡한 객체의 동작을 이해하는 데 필요하다.
  • Activity Diagram
    : 비즈니스 프로세스나 시스템의 작업 흐름을 시각화하는 데 사용된다. 활동은 작업 단계를 나타내며 화살표로 연결된 동작의 흐름을 보여주고 제어 흐름, 의사 결정, 병렬 처리 등을 표현하여 프로세스를 이해하고 분석하는 데 활용된다.

 

설계/구현 매핑

객체지향 모델링에는 크게 네 가지 관계, 연관, 전체/부분, 상속, 사용 관계가 그것인데 이들의 각각의 관계는 클래스 또는 객체가 관계를 맺고 있는 특별한 유형을 의미한다. 이에 각각 살펴보면 다음과 같다.

  • 연관관계 (Association)
    : 클래스 간의 관계이며 어떤 클래스의 객체가 다른 클래스의 객체와 상호작용하는 것을 나타낸다. 연관은 일반적으로 양방향 또는 단방향으로 설정될 수 있고 연관에는 다중성(multiplicity)과 역할(role)이 포함될 수 있다. 다중성은 연관에 참여하는 객체의 수를 나타내며, 역할은 해당 연관에서 객체가 가지는 역할을 의미한다.
  • 전체/부분관계 (Composition/Aggregation)
    : 한 객체가 다른 객체의 부분이 되는 관계로 Composition은 전체와 부분 사이에 강한 소유관계가 있는 경우를 의미하며 전체 객체가 파괴되면 부분 객체도 함께 파괴된다. Aggregation은 더 느슨한 관계로 전체 객체와 부분 객체는 독립적으로 존재할 수 있다. 전체/부분 관계는 다이어그램 상에서 다이아몬드 형태의 다이어그램 요소로 표현한다.
  • 상속 관계 (Inheritance)
    : 상속은 클래스 간의 계층적인 관계를 나타내며 한 클래스가 다른 클래스로부터 속성과 동작을 물려받는 것을 의미한다. 부모 클래스(상위 클래스 또는 기본 클래스)의 특성과 동작을 자식 클래스(하위 클래스 또는 파생 클래스)가 재사용할 수 있도록 하고 이를 통해 코드 재사용성과 확장성을 증가시킬 수 있다.
  • 사용 관계 (Dependency)
    : 한 클래스가 다른 클래스의 기능을 사용하는 관계로서 이 관계에서는 클래스 간에 직접적인 연결이 없으며 주로 메소드의 매개변수나 반환 값 등을 통해 나타난다. 클래스가 다른 클래스의 인터페이스를 사용하여 기능을 구현하는 경우 사용 관계가 형성된다.



시스템/객체 설계

객체지향 설계는 소프트웨어 시스템을 개발하기 위한 계획과 구조를 만드는 과정으로 시스템 설계와 객체 설계는 객체지향 개발의 두 단계로서 각각 전체적인 아키텍처와 개별 객체의 세부 사항을 다룬다. 이 둘은 서로 밀접하게 연관되어 있으며 시스템 설계 단계에서 결정된 아키텍처와 모듈화는 객체 설계 단계에서 각 객체의 역할과 협력을 결정하는 데 사용된다. 따라서 객체지향 설계는 시스템의 기능, 구조, 동작을 종합적으로 고려하여 효율적이고 확장 가능한 소프트웨어 시스템을 개발하는 데 필요하다.

  • 시스템 설계
    : 소프트웨어 시스템 전체의 아키텍처와 구조를 정의하는 단계로 다양한 컴포넌트 간의 관계, 모듈화, 시스템의 구조적인 레이어 등을 결정한다.

    • 시스템 아키텍처 설계: 전체 시스템 아키텍처, 레이어 구조, 서브 시스템 등을 정의하며 시스템의 큰 틀을 잡아내고 시스템의 기능적 요구사항을 충족시키기 위한 아키텍처를 선택한다.
    • 모듈 설계: 시스템을 여러 개별 모듈로 분리하고 각 모듈의 역할과 책임을 정의한다. 이 모듈 간의 인터페이스와 상호작용 방법을 결정하여 시스템 전체의 유기적인 통합을 보장한다.
    • 데이터베이스 설계: 시스템에서 사용되는 데이터의 구조와 관계를 정의하며 데이터의 저장, 검색, 관리 등을 위한 데이터베이스 구조와 스키마를 설계한다.
  • 객체 설계
    : 객체 설계는 시스템 설계의 결과물을 기반으로 각각의 객체와 클래스의 구조, 속성, 메소드 등을 정의하는 단계로서 시스템 설계에서 정의한 모듈을 실제로 구현 가능한 형태로 변환한다.

    • 클래스 정의: 클래스의 속성과 메소드를 정의하고 클래스의 책임과 역할을 명확히 한다. 클래스의 인터페이스와 구현을 결정하여 다른 클래스와의 협력 관계를 구성한다.
    • 객체 간의 관계: 연관, 전체 부분, 상속, 사용 관계 등을 통해 객체 간의 관계를 설정하며 이를 통해 객체들의 협력과 상호작용을 정의한다.
    • 동적 동작 정의: 시퀀스 다이어그램과 같은 다이어그램을 사용하여 객체 간의 상호작용을 시각화하고 메소드 호출 순서와 결과를 정의한다.

 

디자인 패턴

객체지향 설계작업은 방법론이 있지만 쉬운 작업은 아니다. 이를 위해선 많은 경험과 인사이트가 필요하다. 이에 객체 설계의 경험을 토대로 한 디자인패턴 개념이 등장한다. 디자인패턴은 프로그램 개발에 자주 등장하는 문제를 기술하고 같은 작업을 반복하여 설계하지 않고 여러 번 반복하여 사용할 수 있는 문제에 대한 솔루션을 기술한 것이다. 다만 패턴에서 기술된 솔루션이 특정한 구현을 나타낸 것은 아니며 여러 상황에서 적용될 수 있는 템플릿 성격이라고 보는 것이 맞다. 그래서 문제에 대한 설계를 추상적으로 표현하여 문제를 해결하려는 요소들을 일반화하고 잘 정리한 것이다.

이러한 디자인패턴은 다음과 같은 요소로 구성된다.

  • 패턴 이름/구분: 패턴을 부를 때 사용하는 이름과 패턴 유형
  • 문제/배경: 패턴이 사용되는 분야, 배경 및 해결하려는 문제
  • 솔루션: 패턴을 이루는 요소들, 관계, 협동 과정
  • 사례: 적용 사례
  • 결과: 패턴사용 시 얻게 되는 이점이나 영향
  • 샘플 코드: 패턴이 적용된 원시 코드

패턴을 분류하는 기준은 여러 가지나 보통 23개의 세 가지 유형을 가진 Gamma 분류체계가 일반적인데 아래 간략히 소개한다.

  • 생성 패턴: 객체의 생성 과정을 추상화하고 객체 생성과 조합을 통해 시스템을 유연하고 확장 가능하게 만드는 패턴들이다.
    • Singleton 패턴: 클래스의 인스턴스가 하나만 생성되도록 보장
    • Factory Method 패턴: 객체 생성을 서브 클래스로 분리하여 확장성을 갖춤
    • Abstract Factory 패턴: 관련된 객체들의 팩토리들을 추상화하여 함께 사용
    • Builder 패턴: 복잡한 객체의 생성 과정을 분리하여 객체 생성을 간단하게 구성
    • Prototype 패턴: 객체를 복사하여 새로운 객체를 생성하는 사용
  • 구조 패턴: 클래스나 객체를 조합하여 더 큰 구조를 만들거나, 인터페이스를 결합하여 새로운 기능을 제공하는 패턴들이다. 
    • Adapter 패턴: 서로 호환되지 않는 인터페이스를 함께 동작하도록 변환
    • Bridge 패턴: 추상화와 구현을 분리하여 두 개의 독립적인 클래스 계층 구성
    • Composite 패턴: 개별 객체와 복합 객체를 동일한 방식으로 다루도록 정리
    • Decorator 패턴: 객체에 추가적인 기능을 동적으로 추가
    • Facade 패턴: 복잡한 하위 시스템을 단순화된 인터페이스로 노출
  • 행동 패턴: 객체 간의 상호작용과 책임 분배를 중심으로 다루는 패턴들이다. 
    • Strategy 패턴: 알고리즘을 정의하고 각각을 캡슐화하여 교환 가능 제공
    • Observer 패턴: 한 객체의 상태 변경이 다른 객체에 통지
    • Command 패턴: 요청을 객체의 형태로 캡슐화하여 나중에 실행하거나 취소 가능
    • Chain of Responsibility 패턴: 요청을 처리하는 객체들의 연결을 만들어 책임 위임
    • State 패턴: 객체의 상태에 따라 행동을 변경 가능