GGym's Practice Notes

4-3. 프로토타입_프로토타입 팩터리 본문

Design Pattern/Modern C++ 디자인패턴

4-3. 프로토타입_프로토타입 팩터리

GGym_ 2020. 4. 22. 19:25

자주 복제해서 사용할 기본 객체들이 미리 정해져있다면 프로토타입 팩터리를 사용하는 것이 좋을 수 있다.

전역변수를 선언하여 복제해 사용해도 좋겠지만 프로토타입을 저장한 별도의 클래스를 두고 사용자가 원할 때, 목적에 맞는 복제본을 요구받는 시점에 만들어 제공하는 것이다.

struct EmployeeFactory{
    static Contact main;
    static Contact aux;

    static unique_ptr<Contact> NewMainOfficeEmployee(string name, int suite){
        return NewEmployee(name, suite, main);
    }

    static unique_ptr<Contact> NewAuxOfficeEmployee(string name, int suite){
        return NewEmployee(name, suite, aux);
    }

private:
    static unique_ptr<Contact> NewEmployee(string name, int suite, Contact& proto){
        auto result = make_unique<Contact>(proto);
        result->name = name;
        result->address->suite = suite;
        return result;
    }
};
auto john = EmployeeFactory::NewMainOfficeEmployee("John Doe", 123);
auto jane = EmployeeFactory::NewAuxOfficeEmployee("Jane Doe", 125);

팩터리를 사용하면 누락되어 있는 부분들을 사용할 가능성을 줄여준다. 직접 객체가 생성되는 부분을 private으로 두고 EmployeeFactory만 friend로 선언되어 부분적인 생성자를 사용할 수 있게 하면 완전하지 못한 프로토타입을 사용한 객체는 사용될 수 없게 된다.

전체코드

더보기
#include<iostream>
#include<memory>
using namespace std;

struct Address{
    friend class EmployeeFactory;
private:
    string street, city;
    int suite;

    Address(const string& street, const string& city, const int suite)
        : street{street}, city{city}, suite{suite}{}
        
    Address(const Address& address)
        : street{address.street}, city{address.city}, suite{address.suite}{}
        
    friend ostream& operator<<(ostream& os, const Address& obj){
        return os << "street: " << obj.street
                  << " city: " << obj.city
                  << " suite: " << obj.suite;
    }
};

struct Contact{
    friend class EmployeeFactory;
private:
    string name;
    Address* address;  

    Contact() : name(nullptr), address(nullptr){}
    
    Contact& operator=(const Contact& other){
        if(this == &other)
            return *this;
        name = other.name;
        address = other.address;
        return *this;
    }
    Contact(const string name, Address* address)
        : name{name}, address{address}{
    }
    friend ostream& operator<<(ostream& os, const Contact& obj){
        return os << "name: " << obj.name
                  << " address: " << *obj.address;
    }
};

struct EmployeeFactory{
    static Contact main;
    static Contact aux;

    static unique_ptr<Contact> NewMainOfficeEmployee(string name, int suite){
        return NewEmployee(name, suite, main);
    }

    static unique_ptr<Contact> NewAuxOfficeEmployee(string name, int suite){
        return NewEmployee(name, suite, aux);
    }

private:
    static unique_ptr<Contact> NewEmployee(string name, int suite, Contact& proto){
        auto result = make_unique<Contact>(proto);
        result->name = name;
        result->address->suite = suite;
        return result;
    }
};

Contact EmployeeFactory::main{"", new Address{"123 East Dr", "London", 0}};
Contact EmployeeFactory::aux{"", new Address{"123B East Dr", "London", 0}};

int main(){
    auto john = EmployeeFactory::NewMainOfficeEmployee("John Doe", 123);
    auto jane = EmployeeFactory::NewAuxOfficeEmployee("Jane Doe", 125);

    cout << *john << endl << *jane << endl;

    return 0;
}