준비하는 대학생

[Cpp] 클래스 관계 - 연관(association, aggregation, composition) 본문

Programming/C++

[Cpp] 클래스 관계 - 연관(association, aggregation, composition)

Bangii 2023. 3. 8. 09:06

연관(association)

C++에서 클래스 관계를 표현하는 방법 중 하나는 연관(association)이다.

 

연관은 두 클래스 사이의 관계를 나타내며, 한 클래스가 다른 클래스의 객체를 가지고 있는 경우에 해당한다.

예를 들어, '학생(Student)' 클래스와 '과목(Subject)' 클래스가 있다고 가정해 보면 학생은 여러 과목을 수강할 수 있으므로, '학생(Student)' 클래스와 '과목(Subject)' 클래스는 연관 관계를 가지게 된다.

 

연관은 일대일, 일대다, 다대일, 다대다 관계를 모두 나타낼 수 있다.

예를 들어, '한 학생(Student)'은 여러 개의 '과목(Subject)'을 수강할 수 있지만, '한 과목(Subject)'은 여러 명의 '학생(Student)'에게 수강될 수 있으므로, '학생(Student)' 클래스와 '과목(Subject)' 클래스는 다대다 관계를 가질 수 있다.

 

연관 관계는 클래스 다이어그램(Class Diagram)을 사용하여 표현된다.

연관 관계는 화살표를 사용하여 나타내며, 화살표가 가리키는 쪽이 연관 관계를 가지는 클래스이다. 예를 들어, '학생(Student)' 클래스와 '과목(Subject)' 클래스가 연관 관계를 가진다면, '학생(Student)' 클래스 쪽에 화살표가 나타나고, 화살표가 '과목(Subject)' 클래스를 가리키게 된다.

아래는 위의 학생(Student)' 클래스와 '과목(Subject)' 클래스가 연관 관계를 클래스 다이어그램으로 표현한 것이다.

 

 

위 관계를 보면 화살표와 글자로 나타내고 있다. 그리고 다중성을 숫자로 표시한 것이 있는데 이는 연관과 관련된 객체의 수를 나타낸다.

다중성은 아래의 표와 같이 표현한다.

 

표현 설명
n n개의 객체
* 0개 이상의 객체
0...1 0~1개의 객체
n...m n~m 범위의 객체
n,m n개 또는 m개의 객체

 

일반적으로 위와 같이 서로 여러개의 객체를 가질 수 있는 다대다 연관관계를 그대로 구현하지는 않는다. 

다대다 관계를 그대로 구현하면 순환에 의해 무한 참조가 발생하기 때문이다.

그래서, 학생 객체에서 과목 객체 자체가 아니라 과목의 이름만 저장하고, 과목 객체에서는 학생의 이름만 저장하는 형태로 따로 구현한다. 

 

이러한 연관관계는 소유(aggregation)와 구성(composition)으로 구분할 수 있다.

 소유(aggregation)

소유(Aggregation) 관계는 전체 객체와 부분 객체의 관계를 나타낸다.

소유관계는 구성 관계와 유사하지만, 전체 객체와 부분 객체의 생명주기가 독립적이다.

즉, 전체 객체가 파괴되더라도 부분 객체는 파괴되지 않는다.

 

예를 들어, '회사(Company)' 클래스와 '직원(Employee)' 클래스가 있다고 가정해 보자.

회사는 여러 명의 직원을 가지고 있으며, 직원은 여러 회사에서 일할 수 있다. 따라서 '회사(Company)' 클래스와 '직원(Employee)' 클래스는 소유관계를 가지게 된다.

 

한 회사가 없어져도 해당 직원은 다른 회사에서도 사용하고 있으므로 해당 객체가 사라지지는 않는다.

따라서 '회사(Company)' 클래스와 '직원(Employee)' 클래스는 생명주기가 서로 독립적이다.

 

소유관계는 클래스 다이어그램에서 비어있는 마름모로 표시됩니다. 전체 객체 쪽에 마름모가 그려져 있으며, 화살표가 부분 객체 쪽으로 향한다.

다음은 '회사(Company)' 클래스와 '직원(Employee)' 클래스가 소유관계를 가지는 클래스 다이어그램의 예시이다.

 

다음은 위의 관계를 코드로 나타낸 것이다.

class Employee {
  // ...
};

class Company {
  private:
    std::vector<Employee*> employees; // 직원 객체에 대한 포인터를 저장하는 vector
  public:
    // 직원 객체를 추가하는 메서드
    void addEmployee(Employee* employee) {
      employees.push_back(employee);
    }
    // ...
};

위 코드에서 'Company' 클래스는 'Employee' 클래스의 포인터를 저장하는 벡터를 가지고 있다.

그리고, 'Company' 객체가 파괴될 'Employee' 객체가 함께 파괴되지 않는다. 

따라서 'Company' 클래스와 'Employee' 클래스는 소유관계임을 알 수 있다.

 

구성(composition)

구성(Composition) 관계는 전체 객체와 부분 객체의 강한 연결 관계를 나타낸다.

구성 관계에서는 전체 객체와 부분 객체가 강하게 결합되어 있어, 전체 객체가 파괴될 때 부분 객체도 함께 파괴됩니다. 즉, 전체 객체와 부분 객체는 생명주기를 공유한다.

예를 들어, '차(Car)' 클래스와 '바퀴(Wheel)' 클래스가 있다고 가정했을 때 하나의 차는 여러 개의 바퀴를 가지며, 바퀴는 차 없이는 존재할 수 없다. 따라서 '차(Car)' 클래스와 '바퀴(Wheel)' 클래스는 구성 관계를 가지게 된다.

 

물론 이는 주관적인 관계이기 때문에 보는 차가 없어도 바퀴가 독립적으로 존재할 수 있다고 생각할 수 있다. 하지만 프로그램을 만들었을 때 해당 객체의 생명주기를 공유 즉 같이 생성되고 샅이 파괴된다면 이는 구성 관계라고 볼 수 있다.

 

구성 관계는 클래스 다이어그램에서 채워진 마름모로 표시된다. 전체 객체 쪽에 마름모가 그려져 있으며, 화살표가 부분 객체 쪽으로 향한다. 다음은 '차(Car)' 클래스와 '바퀴(Wheel)' 클래스가 구성 관계를 가지는 클래스 다이어그램의 예시이다.

 

다음은 위의 관계를 코드로 나타낸 것이다.

 

class Wheel {
  // ...
};

class Car {
  private:
    Wheel* wheels[4]; // 바퀴 객체에 대한 포인터를 저장하는 배열
  public:
    // 생성자에서 바퀴 객체를 생성
    Car() {
      for (int i = 0; i < 4; i++) {
        wheels[i] = new Wheel();
      }
    }
    // 소멸자에서 바퀴 객체를 삭제
    ~Car() {
      for (int i = 0; i < 4; i++) {
        delete wheels[i];
      }
    }
    // ...
};

 

코드에서 'Car' 객체가 생성될 , 생성자에서 'Wheel' 객체를 동적으로 생성하고 포인터 배열에 저장한다.

반면, 'Car' 객체가 파괴될 , 소멸자에서 'Wheel' 객체를 삭제된다. 이때, 'Wheel' 객체의 생성과 삭제는 'Car' 객체와 함께 이루어지므로, 'Car' 객체와 'Wheel' 객체는 생명주기를 공유한다.

즉 두 클래스는 구성 관계를 갖다고 할 수 있다.

 

클래스는 상속만으로 표현할 수는 없다. 따라서 다양한 표현들을 사용하는데 이번에 소유와 구성의 연관관계를 공부해보았다. 

다음에는 이보다 약한 관계인 의존관계에 대해 알아보겠다.

 

 

'Programming > C++' 카테고리의 다른 글

[Cpp] 다형성  (0) 2023.03.10
[Cpp] 클래스 관계 - 상속  (0) 2023.03.06
Comments