[10] 객체들 사이의 관계

gyeolse·2021년 12월 14일

C++

목록 보기
2/3

홍정모의 따라하며 배우는 C++ 를 수강하며 정리한 글입니다.

10.1 객체들의 관계

관계를 표현하는 동사관계의 형태다른 클래스에 속할 수 있는가?멤버의 존재를 클래스가 관리?방향성
구성Part of전체/부품NOYES단방향
집합Has a전체/부품YESNO단방향
연계,제휴Uses-a용도 외엔 무관YESNO단방향 Or 양방향
의존Depends-on용도 외엔 무관YESYES단방향

10.2 구성 관계

한 클래스가 다른 클래스의 부품이 되는 경우. B is Part of A.

예시로 Monster, Position2D Class가 있다고 가정하자. 이때, Position2D Class는 Monster Class의 위치를 나타내는 일부분이라고 볼 수 있다. 이 때 Position2D 자체는 재사용이 되는데, Monster에 들어있는 Position2D 의 값은 다른 곳에서 절대 쓸 일이 없다. 즉 다른 클래스에 속할 수 없다는 것이다.
방향성은 단방향이다. Monster 클래스가 작업할 때, Position2D 클래스 내에서 작업을 진행 할 때, Monster class가 어떤지 알아야한다면, 그 작업이 잘못된 것이다.

예제코드

#include <string>
#include "Position2D.h"
using namespace std;

class Monster {
private:
    std::string m_name;

    // int m_x; int m_y;
    Position2D m_location;

public:
    // Monster(const std::string name_in, const int& x_in, const int& y_in)
    //     : m_name(name_in), m_x(x_in), m_y(y_in) {}
    Monster(const std::string name_in, const Position2D& pos_in) : m_name(name_in), m_location(pos_in)
    {}

	// void moveTo(const int& x_target, const int& y_target) {
    //     m_x = x_target;
    //     m_y = y_target;
    // }

    void moveTo(const Position2D& pos_target) {
        m_location.set(pos_target);
    }


    friend std::ostream& operator  << (std::ostream& out, const Monster& monster) {
        out << monster.m_name << monster.m_location << std::endl;
    }
};
class Position2D {
private:
    int m_x;
    int m_y;

public:
    Position2D(const int& x_in, const int& y_in)
        : m_x(x_in), m_y(y_in)
    {}
    
    void set(const Position2D& pos_target) {
        set(pos_target.m_x, pos_target.m_y);
        // m_x = pos_target.mx;
        // m_y = pos_target.my; 라고 하는 것 보다는, 재활용하는 것이 더 좋음. 
    }

    void set(const int& x_target, const int& y_target) {
        m_x = x_target;
        m_y = y_target;
    }


    // monster의 output opertator
    friend std::ostream& operator  << (std::ostream& out, const Position2D& pos2d) {
        out << pos2d.m_x << " " << pos2d.m_y << std::endl;
        return out;
    }
};

10.3 집합 관계 ( Aggregation )

집합 관계를 구성(composition) 관계로 구현하려면, 동기화 시켜주는 과정이 필요하다. 하지만 클래스를 나눠줌으로써 집합 관계를 편하게 구현할 수 있다. 예를 들어서 lecture에 대한 것을 정의한다면, lecture에 속한 student, teacher를 클래스로 나눠준다.

10.4 제휴 관계 ( Association )

어느 쪽이 확실히 주가 되고, 부가 되는지 명확하지 않은 상황.

둘 다 주 이거나, 둘 다 부인 경우! 서로가 서로를 관리하지 못한다.
Doctor 클래스와 Patient 클래스가 있다고 가정하자. 이때 Patient, Doctor 클래스에 각각 서로를 추가하는 addDoctor addPatient 함수를 추가해야하고, 서로 meetDoctors,meetPatients 함수를 각각 구현해야 한다. add 함수는 각각 호출해야 하며, meet 함수 역시 각각 호출이 진행되어야 한다. 주로, forward declaration 되어 있는 경우, 둘 다 동등한 관계인 Association 관계라고 받아들이면 쉬울 것이다.

예제 코드

#include <bits/stdc++.h>
using namespace std;

class Doctor; // forward declaration. 

class Patient {
private:
    string m_name;
    vector<Doctor*> m_doctors;
public:
    Patient(string name_in) : m_name(name_in) {}

    void addDoctor(Doctor* new_doctor) {
        m_doctors.push_back(new_doctor);
    }

    //현 상황에서 meetDoctors 내의 알 방법이 X 그래서 분리해야함.
    void meetDoctors();
    friend class Doctor;
};

class Doctor {
private:
    string m_name;
    vector<Patient*> m_patients;
public:
    Doctor(string name_in) : m_name(name_in) {}
    ~Doctor();
    void addPatient(Patient* new_patient) {
        m_patients.push_back(new_patient);
    }

    void meetPatients() {
        for (auto& ele : m_patients) {
            cout << "Meet Doctor : " << ele->m_name << endl;
        }
    }

    friend class Patient; //friend로 추가해두자
};

void Patient::meetDoctors() { //별도로 분리해서 구현
    for (auto& ele : m_doctors) {
        cout << "Meet Patient : " << ele->m_name << endl;
    }
}

int main() {
    Patient* p1 = new Patient("Jack Jack");
    Patient* p2 = new Patient("Dash");
    Patient* p3 = new Patient("Violet");

    Doctor* d1 = new Doctor("Doctor K");
    Doctor* d2 = new Doctor("Doctor L");

    p1->addDoctor(d1);
    d1->addPatient(p1);

    p2->addDoctor(d2);
    d2->addPatient(p2);

    p2->addDoctor(d1);
    d1->addPatient(p2);

    // Patients meet doctors
    // doctors meet patients
    p1->meetDoctors();
    d1->meetPatients();
}

10.5 의존 관계 ( dependency )

서로 간의 연결강도가 약하다.

Worker 클래스와 Timer 클래스가 있다고 가정해보자. Worker 클래스를 선언할 때, Timer 클래스에 대해서 알고 있어야 할 필요가 없다. class level 에서 몰라도 되고, 구현한 단계에서만 사용이 된다. 가져다 쓰는 거라고 생각하면 쉽다.

10.6 Container Class

다른 클래스를 담는 역할을 하고 있다.

std::vector .... std::array ..... list pair queue .... 정말 다양한 컨테이너들이 존재한다.

0개의 댓글