스토리텔링 개발자

[Effective C++] 38. 객체 합성 본문

개발/Effective C++

[Effective C++] 38. 객체 합성

김디트 2024. 7. 8. 11:07
728x90

항목 38 : “has a(~는 ~를 가짐)” 혹은 “is implemented in terms of(~는 ~를 써서 구현됨)”를 모형화할 때는 객체 합성을 사용하자.

 

 

 

합성(composition)
  • 객체가 다른 타입의 객체를 포함하고 있을 경우 성립하는 타입들 사이의 관계
  • 레이어링(layering), 포함(containment), 통합(aggregation), 내장(embedding) 등으로도 불린다.
class Address { ... };
class PhoneNumber { ... };
class Person
{
public:
    ...
private:
    // 아래 객체들은 Person 객체와 합성 관계이다.
    string name;
    Address address;
    PhoneNumber voiceNumber;
    PhoneNumber faxNumber;
};

 

 

 

객체 합성의 의미 두 가지
  • 상속의 의미
    • is a(...는 ...의 일종이다.)
  • 합성의 의미
    • has a(...는 ...를 가진다.)
    • is implemented in terms of(...는 ...를 써서 구현된다.)
  • 뜻이 두 가지인 이유는, 소프트웨어 개발에서 우리가 대하는 영역(domain)이 두 가지이기 때문이다.

 

 

 

영역의 종류
  • 응용 영역(application domain)
    • 객체 중 일상 생활에서 볼 수 있는 사물을 본 뜬 것들.
    • 사람, 이동수단, 비디오 프레임 등.
    • has a
  • 구현 영역(implementation domain)
    • 시스템 구현만을 위한 인공물.
    • 버퍼, 뮤텍스, 탐색 트리 등.
    • is implemented in terms of

 

 

 

예제로 알아보는 is-a 관계와 is-implemented-in-terms-of 관계의 차이점
  • set 템플릿을 사용하려는 경우에 대해 생각해보자.
    • std::set의 경우 원소 한 개당 포인터 세 개의 오버헤드가 걸리는 것이 마음에 걸린다.
      • 균형 탐색 트리(balanced search tree)로 구현되어 있기 때문.
    • set 템플릿을 만들되 list에서 파생된 형태부터 시작하도록 만들어보자.
    • template<typename T> // list를 잘못 사용하는 방법
      class Set : public std::list<T> { ... };
    • 허나, list와 set은 is-a 관계가 될 수 없다.
      • list는 중복 원소를 가질 수 있는 컨테이너이기 때문이다.
    • set 객체는 list 객체를 써서 구현되는(is implemented in terms of) 형태의 설계가 되어야 한다.
    • template<class T>
      class Set
      {
      public:
          bool member(const T& item) const;
          
          void insert(const T& item);
          void remove(const T& item);
          
          std::size_t size() const;
      private:
          std::list<T> rep; // list를 합성
      };
      
      template<typename T>
      bool Set<T>::member(const T& item) const
      {
          return std::find(rep.begin(), rep.send(), item) != rep.end();
      }
      
      template<typename T>
      void Set<T>::insert(const T& item)
      {
          if(!member(item)) rep.push_back(item);
      }
      
      template<typename T>
      void Set<T>::remove(const T& item)
      {
          typename std::list<T>::iterator it = std::find(rep.begin(), rep.end(), item);
          
          if(it != rep.end()) rep.erase(it);
      }
      
      template<typename T>
      std::size_t Set<T>::size() const
      {
          return rep.size();
      }
728x90
Comments