Super Kawaii Cute Cat Kaoani
본문 바로가기
💾 lecture/소프트웨어분석 및 설계

[소프트웨어분석 및 설계] UML과 OOP

by wonee1 2025. 6. 29.
728x90

 

구현의 고려사항


  1. 모델과 구현 언어 간 개념의 불일치
  2. 모델의 분리된 뷰의 통합
  3. 구현의 효율성 문제

 

UML의 필요성


  1. UML은 소프트웨어 개념을 다이어그램으로 표기하기 위한 시각적인 기법(표기법)
  2. UML의 용도 - 문제 도메인 ,설계 제안, 구현에 관한 다이어그램을 그릴
  3. 설계를 바탕으로 코딩(구현)이 이루어진다
  4. UML의 클래스와 OOP(c++, JAVA, EJB)와의 관계를 이해할 필요가 있음

 

개념과 명세


개념 차원의 다이어그램은 추상 개념 서술 용도로 활용

→ 이 경우 다이어그램은 의미론적 규칙에 얽매이지 않음

EX) 개념 상속에서 Dog은 Animal의 특수한 경우임을 나타내는 것 이상 없음

 

하지만 명세 용도의 다이어그램은 프로그램의 일부를 실제로 서술하는데 사용

→ 구현의 가이드로 사용될 경우 더 많은 부분의 정보 전달

상속 관계


C++ 은 : public,  Java는 extends로 상속 관계를 표현한다! 

 

 

 

 

다중상속


다중 상속(Multiple Inheritance)은 언어마다 지원 여부에 차이가 있음

  • Java는 클래스 상속에서 다중 상속을 지원하지 않음
  • 예시: Platypus (포유류이면서 동시에 멸종위기 동물)

Platypus는 두 상속 계층을 동시에 따름

  • Mammal → Platypus
  • Endangered → Platypus
💡다중상속이란?
하나의 클래스가 둘 이상의 클래스로 부터 상속 받는 것

 

다중상속의 표현


상속 에 따른 생성자 처리를 판단해야하는 경우 발생

  • Platypus는 Mammal과 Endangered를 동시에 상속
  • C++에서는 여러 부모 클래스의 생성자를 명시적으로 호출해야 함

 

Platypus::Platypus() : Mammal(), Endangered() {
    // Platypus 초기화 코드
}

 

 

 

집합관계


● 개념

  • 집합관계는전체(Whole) - 부분(Part)” (has -a, part-of)관계
  • 여기서는 Polygon이 여러 개의 Point 객체를 포함
  • 전체가 없어져도 부분은 독립적으로 존재 가능→ 느슨한 관계

● UML 표현

  • 빈 마름모(◇)는 Aggregation을 의미
  • Polygon ↔ Point
    • 1개의 Polygon은 3개 이상의 Point를 가짐 (3..*)

● 코드 예시

 

C++ 표현

class Polygon {
private:
    Point* points[max];  // 포인터 배열로 관계 표현
};

 

Java 표현

public class Polygon {
    private Point[] points;

    public Polygon() {
        points = new Point[max];  // 참조로 관계 설정
    }
}

 

 

핵심 정리

언어
집합관계 구현 방식
C++
포인터로 Point를 참조
Java
객체 배열 또는 컬렉션으로 Point를 참조

 

 

 

 

집합 연관



class Person {
public:
    Person(char* n, char s, int a);  // 생성자
    ~Person() {};                   // 소멸자

private:
    char name[40];   // 이름
    Person* spause;  // 배우자 (binary relationship)
    Body* body;      // 몸통에 대한 포인터 (Aggregation)
    Hand* l_hand;    // 왼손에 대한 포인터
    Hand* r_hand;    // 오른손에 대한 포인터
};
멤버
관계 유형
설명
Person* spause
연관관계 (Association)
서로 연결된 두 사람 간의 관계 (예: 결혼)
Body* body
집합관계 (Aggregation)
Person이 Body를 포함하지만, Body는 독립적으로 존재 가능
Hand* l_hand / r_hand
집합관계
손 객체는 별도로 존재하며 Person에 "소속"됨

 

 

복합 연관


class Person {
public:
    Person(char* n, char s, int a);
    ~Person() {};
    
private:
    char name[40];
    
    Person* spause;  // 연관관계 (binary relationship)

    Body body;       // 합성관계 (객체 포함)
    Hand l_hand;     // 합성관계 (왼손 객체 직접 포함)
    Hand r_hand;     // 합성관계 (오른손 객체 직접 포함)
};
멤버
관계
설명
Person* spause
연관관계 (association)
포인터로 다른 사람 참조 (독립 존재 가능)
Body body
합성관계 (composition)
Person에 포함된 객체, 생명주기 공유
Hand l_hand, r_hand
합성관계
객체 내부에 직접 포함됨, Person이 소멸되면 같이 소멸됨

 

 

연관의 표현


cClass

  • 중심 클래스. 아래의 세 가지 관계를 모두 가짐:
    • cPart와 합성 관계 (composition)
    • cAssoc과 연관 관계 (association)
    • cExtended로부터 상속됨 (inheritance)
class cClass {
private:
    int _c;
    cPart _Part;          // 합성관계 (객체 포함)
    cAssoc* _Assoc_PTR;   // 연관관계 (포인터로 참조)
public:
    set1(int n) { _c = n; }
    set2(int n) { _Part.set(n); }              // 포함된 객체 사용
    set3(int n) { _Assoc_PTR->_a = n; }        // 연관된 객체 사용
};

class cPart {
private:
    int _p;
public:
    set(int n) { _p = n; }
};

class cAssoc {
private:
    int _a;
public:
    set(int n) { _a = n; }
};

class cExtended : public cClass {
private:
    int _e;
public:
    set(int n) { _e = n; }
};

 

 

 

파생클래스


const int Max = 20;

class Manager : public Employee {
public:
    Manager(char* n, char s, int a, int n = 0) : Employee(n, s, a, n) {
        for (int i = 0; i < Max; i++) group[i] = 0;
    }

    Employee* getEmployee(int n) { return group[n]; }

    void setEmployee(Employee* e, int a) { group[a] = e; }

    ~Manager() { delete[] group; }

private:
    Employee* group[Max]; // Manager : Employee 1대 다 관계 
};
  • Manager는 Employee를 상속받은 파생 클래스
  • Manager는 Employee* group[Max] 배열을 통해 여러 명의 Employee 객체를 관리
    • 즉, Manager → 다수 Employee : 1:N 연관 관계
  • 생성자에서는 group 배열을 초기화하고, 소멸자에서 delete[] group 호출
 
main() {
    Employee ed("Edward", 'm', 21, 20000);
    ed.setSalary(25000);  // 급여 인상

    Manager jane("Jane", 'f', 25);
    jane.setSalary(100000);  // 매니저는 높은 급여

    jane.setEmployee(&ed, 0);  // Edward를 0번 인덱스로 그룹에 등록

    ed.setSalary(15000);  // Edward 급여를 다시 낮춤
}
  • Employee 객체 ed와 Manager 객체 jane을 각각 생성
  • jane은 자신의 group[0]에 ed를 저장함 (포인터 연결)
  • jane은 ed의 직접 소유자가 아닌 연결된 관계
  • 이후 ed의 급여는 개별적으로 다시 수정됨 → 독립 객체

 

추상클래스


 

class Item {
public:
    virtual void cut() = 0;
    virtual void move(Length dx, Length dy) = 0;
    virtual Boolean pick(Length px, Length py) = 0;
    virtual void ungroup() = 0;
}; // 인터페이스 virtual 키워드 사용 

class Shape : public Item {
public:
    void cut() = 0;
    void draw() { write(Color_Foreground); }
    void erase() { write(Color_Background); }
    void move(Length dx, Length dy) { x += dx; y += dy; }
    virtual Boolean pick(Length px, Length py) = 0;
    void ungroup() = 0;
    virtual void write(Color color) = 0;

protected:
    Length x, y;
};

class Box : public Shape {
public:
    Box(Length x0, Length y0, Length w, Length h) : Shape() { ... }
    Boolean pick(Length px, Length py) { ... }
    void move(Length dx, Length dy) { ... }

protected:
    Length width, height;
};

class Circle : public Shape {
public:
    Circle(Length x0, Length y0, Length radius) : Shape() { ... }
    Boolean pick(Length px, Length py) { ... }
    void move(Length dx, Length dy) { ... }
    void write(Color color) { ... }

protected:
    Length radius;
};


Box, Circle는 Shape의 추상 메서드를 구현하는 구체 클래스
Circle은 write()까지 구현하여 완전히 인스턴스화 가능
Box는 write()가 없음 → 여전히 추상 클래스일 가능성 있음
  • Item: 공통 인터페이스 제공
  • Shape: 위치(x, y) 등 공통 속성과 일부 기능을 구현한 중간 추상 클래스
  • Box, Circle: 도형별 구현을 제공하여 실제 사용할 수 있는 클래스

추상 클래스 c ++ 에선 virtual로 , Java에선 abstract로 표현한다 

 

 

 

이진 연관


class Person {
public:
    Person(char* n, char s, int a);     // 생성자
    Person* getSpouse() { return spouse; }
    void setSpouse(Person* p);          // 배우자 설정 함수
    ~Person() {}
private:
    char name[40];
    char sex;
    int age;
    Person* spouse;                    // 배우자 관계를 가리키는 포인터
};

//spouse: 해당 객체가 연결된 다른 Person 객체를 가리킴
//양방향 이진 연관 관계를 구현하고자 함 (A ↔ B 형태)

void Person::setSpouse(Person* p)
{
    if (spouse != p) {                      // 이미 같은 사람이면 무시
        if (spouse == 0) {                  // 현재 배우자가 없다면
            spouse = p;                     // 새 배우자 설정
            p->setSpouse(this);             // 상대도 나를 배우자로 설정 (결혼)
            return;
        }

        // 현재 배우자가 나와 연결 안 되어 있으면 이혼 처리
        if (spouse->getSpouse() != this) {
            Person* old = spouse;           // 기존 배우자 임시 저장
            spouse = 0;                     // 나의 배우자 끊기
            old->setSpouse(0);              // 상대의 배우자도 끊기
        }

        spouse = p;                         // 새 배우자 설정
        if (spouse != 0) {
            spouse->setSpouse(this);        // 상대도 나를 배우자로 설정
        }
    }
}

상황
처리
spouse == p
이미 배우자일 경우 아무것도 하지 않음
현재 배우자가 없음 (spouse == 0)
p를 배우자로 설정하고, p도 나를 배우자로 설정함 (결혼)
현재 배우자가 있고, spouse->getSpouse() != this
한쪽만 배우자 설정한 상태 → 서로 이혼 처리
새로운 배우자 설정 후
spouse->setSpouse(this) 호출로 상대방도 양방향 연관 유지

 

 

다대일 연관


class Person {
public:
    Person(char* n, char s, int a);
    
    Person* getFather()  { return father; }
    Person* getMother()  { return mother; }
    Person* getChildren();  // (정의는 생략됨)

    void addChild(Person* p) {
        children.insert(p);
    }

    void setFather(Person* p) {
        father = p;
        if (p) {
            p->addChild(this);
            return;
        }
    }

    void setMother(Person* p) {
        mother = p;
        if (p) {
            p->addChild(this);
            return;
        }
    }

    ~Person() {}

private:
    char name[40];
    char sex;
    int age;
    Person* father;
    Person* mother;
    Set children;  // 자녀 목록 저장 (insert 메서드 사용 가능)
};
관계
구현 방식
자식 → 부모
father, mother 포인터 (다대일)
부모 → 자식
children 집합(Set) (일대다)
동기화
부모를 설정하면 addChild(this)로 자동 연결

 

  • setFather(p) 또는 setMother(p) 호출 시:
    • this 객체의 부모 포인터 설정 (father = p)
    • 부모 객체의 자식 목록에 this를 추가 (p->addChild(this))
  • addChild(p):
    • children 집합에 해당 자식 p를 추가함

 

다대다 연관

 


  • 하나의 Person은 여러 Company에 소속될 수 있고
  • 하나의 Company도 여러 Person을 고용할 수 있음
  • 독립적인 연관 객체(Association Object) 사용
    • 중간에 있는 사각형은 연관 테이블 또는 클래스 (예: Employment)
    • 각각의 row는 Person과 Company 사이의 하나의 관계를 나타냄
  • 포인터 또는 참조를 양쪽 모두 보유
    • Employment 객체는 Person과 Company 모두를 참조함
    • 이 방식은 관계 자체에 속성(예: 입사일, 직급)을 추가할 수 있는 유연함 제공
728x90