KoreanFoodie's Study

디자인 패턴 (GOF) #5 - Dependency Injection Principle (의존성 역전 원리) 본문

Game Dev/Design Patterns

디자인 패턴 (GOF) #5 - Dependency Injection Principle (의존성 역전 원리)

GoldGiver 2022. 6. 8. 10:48

GoF 의 디자인 패턴강의를 참고하여 디자인 패턴에 대한 내용을 정리하고 있습니다.

Dependency Injection Principle (의존성 역전 원리)

부모 - 자식 관계를 설정하는 Relationship 클래스와 관계를 검색하는 Research 클래스가 있다고 가정해보자. 다음과 같이 코드를 짠다면 어떨까?

#include <iostream>
#include <string>
#include <vector>
#include <tuple>
using namespace std;

// A. High-level modules should not depend on low-level modules.
//    Both should depend on abstractions.
// B. Abstractions should not depend on details. 
//    Details should depend on abstractions.

enum class Relationship
{
    parent,
    child,
    sibling
};

struct Person
{
    string name;
};

struct Relationships // low-level
{
    vector<tuple<Person, Relationship, Person>> relations;

    void add_parent_and_child(const Person& parent, const Person& child)
    {
        relations.push_back({ parent, Relationship::parent, child });
        relations.push_back({ child, Relationship::child, parent });
    }
};

struct Research // high-level
{
      Research(const Relationships& relationships)
      {
        auto& relations = relationships.relations;
        for (auto&& [first, rel, second] : relations)
        {
          if (first.name == "John" && rel == Relationship::parent)
          { 
            cout << "John has a child called " << second.name << endl;
          }
        }
      }
};

int main()
{
    Person parent{ "John" };
    Person child1{ "Chris" };
    Person child2{ "Matt" };

    Relationships relationships;
    relationships.add_parent_and_child(parent, child1);
    relationships.add_parent_and_child(parent, child2);

    Research _(relationships);

    return 0;
}

위의 코드에서, Research 는 high-level 임에도 불구하고, 구현을 보면 RelationShips 클래스의 내부 구조에 직접적으로 의존하고 있음을 알 수 있다.

 

이를 해결하고, high-level 에서는 abstraction 이 detail 에 의존하지 않도록 refactoring 을 하면 다음과 같이 고칠 수 있다.

struct RelationshipBrowser
{
  virtual vector<Person> find_all_children_of(const string& name) = 0;
};

struct Relationships : RelationshipBrowser // low-level
{
  vector<tuple<Person, Relationship, Person>> relations;

  void add_parent_and_child(const Person& parent, const Person& child)
  {
    relations.push_back({parent, Relationship::parent, child});
    relations.push_back({child, Relationship::child, parent});
  }

  vector<Person> find_all_children_of(const string &name) override
  {
    vector<Person> result;
    for (auto&& [first, rel, second] : relations)
    {
      if (first.name == name && rel == Relationship::parent)
      {
        result.push_back(second);
      }
    }
    return result;
  }
};

struct Research // high-level
{
  Research(RelationshipBrowser& browser)
  {
    for (auto& child : browser.find_all_children_of("John"))
    {
      cout << "John has a child called " << child.name << endl;
    }
  }
};

Relationships 내부에 정의된 find_all_children_of 함수를 사용함으로써 Research 라는 high-level 클래스가 더는 Relationships 라는 low-level 모델에 의존하지 않게 되었다!

Comments