728x90

객체는 우리가 생각하는 대로 한 번에 생성되는 것이 아니라 객체를 생성할 때는 객체를 구성하는 데이터 멤버들을 일일이 생성하는 과정을 거치게 됩니다. 그런데 이렇게 클래스의 생성자에서 객체를 생성하는 것이 아닌 객체를 구성하는 부분을 따로 생성하여 조합하는 것이 효율적일 때가 있습니다.

 

먼저 객체를 생성하고 그 객체를 인자로 전달하여 작업을 진행하는 것으로 설계를 할 수 있습니다.

class Phone { 
    QString sOSName;
    QString sPhoneName;
    int nPhonePrice;
public:
    void setOSName(QString sName) { sOSName = sName; }
    void setPhoneName(QString sName) { sPhoneName = sName; }
    void setPhonePrice(int nPrice) { nPhonePrice = sPrice; }
};

QString getOSName(QString sModelCode)
{
    if ( sModelCode == "A01" ) { return "Win"; }
    else if ( sModelCode == "A02" ) { return "Linux"; }
}

QString getPhoneName(QString sModelCode)
{
    if ( sModelCode == "A01" ) { return "Galaxy"; }
    else if ( sModelCode == "A02" ) { return "Galaxy2"; }
}

int getPhonePrice(QString sModelCode)
{
    if ( sModelCode == "A01" ) { return 100; }
    else if ( sModelCode == "A02" ) { return 110; }
}

void SetInfo(Phone& ph, QString sModelCode)
{
    ph.setOSName(getOSName(sModelCode));
    ph.setPhoneName(getPhoneName(sModelCode));
    ph.setPhonePrice(getPhonePrice(sModelCode));
    ...;
}    

int main()
{
    Phone ph;		// 먼저 객체 생성
    QString sPhoneCode = getModelCode();		// 모델 코드를 구하는 함수가 있다고 가정 
    SetInfo(ph, sPhoneCode);
    ...;
}

위 처럼 Phone이라는 객체를 먼저 생성 후 추후 ModelCode를 얻어와 그에 따른 부가적인 설정을 해주는 코드입니다. 만약 추후에 Phone에 설정해야 할 항목이 추가된다면 내부적으로 호출되는 함수들을 일일이 찾아 새로 작성하고 테스트해야 할 것입니다. 이러한 번거로움을 방지하기 위해 위 역할을 담당하는 클래스를 만드는 것입니다.

class Phone {
private:
    QString sOSName;
    QString sPhoneName;
    int nPhonePrice;
public:
    void setOSName(QString sName) { sOSName = sName; }
    void setPhoneName(QString sName) { sPhoneName = sName; }
    void setPhonePrice(int nPrice) { nPhonePrice = sPrice; }
};

class SettingInfo {
private:
	Phone ph;
public:
    void SetInfo(QString sModelCode) {
    	ph = _ph;
        setOSName(sModelCode);
    	setPhoneName(sModelCode);
    	setPhonePrice(sModelCode);
    	...;
    }
    void setOSName(QString sName) { 
    	if ( sModelCode == "A01" ) { ph.setOSName("Win"); }
    	else if ( sModelCode == "A02" ) { ph.setOSName("Linux"); } 
    }
    void setPhoneName(QString sName) { 
    	if ( sModelCode == "A01" ) { ph.setPhoneName("Galaxy"); }
    	else if ( sModelCode == "A02" ) { ph.setPhoneName("Galaxy2"); } 
    }
    void setPhonePrice(int nPrice) { 
    	if ( sModelCode == "A01" ) { ph.setPhonePrice(100); }
    	else if ( sModelCode == "A02" ) { ph.setPhonePrice(110); }  
    }
    Phone results() {
    	return ph;
    }    
}

class Director {
    void SetInfo(SettingInfo& setting, QString sModelCode) {
    	settings.SetInfo(sModelCode);
    }
};

int main()
{
    Director d;
    SettingInfo settings;
    d.SetInfo(settings, getModelCode());
    
    Phone ph = settings.result();
    ...;
}

위 코드에서 Director 클래스는 모델 코드를 선별하고 실제 설정은 SettingInfo에서 해주고 있습니다. 여기서 SettingInfo 같은 클래스를 Builder 클래스라고 합니다. 두 클래스로 분리했기 때문에 각 역할에 변경 요청 시 독립적이기 때문에 변경이 용이하다는 점입니다.

 

만약 여기서 새로운 모델이 출시된다면 SettingInfo 안의 멤버 함수를 일일이 추가해줘야 합니다. 마지막으로 이러한 번거로움을 해결할 방법은 상속을 이용하는 방법입니다. 공통 SettingInfo 클래스의 자식으로 모델의 SettingInfo를 구성하면 인터페이스는 그대로 가져간 채로 사용할 수 있습니다. 만약 새로운 모델이 추가된다면 SettingInfo를 상속받는 모델 SettingInfo를 구성하면 됩니다.

class Phone {
private:
    QString sOSName;
    QString sPhoneName;
    int nPhonePrice;
public:
    void setOSName(QString sName) { sOSName = sName; }
    void setPhoneName(QString sName) { sPhoneName = sName; }
    void setPhonePrice(int nPrice) { nPhonePrice = sPrice; }
};

class SettingInfo {
proteced:
	Phone ph;
public:
    void SetInfo() {
    	ph = _ph;
        setOSName();
    	setPhoneName();
    	setPhonePrice();
    }
    Phone results() { return ph; }    
    void setOSName() = 0 ;
    void setPhoneName() = 0;
    void setPhonePrice() = 0;
}

class A01ModelSettingInfo : public SettingInfo {
public:
    void setOSName() { ph.setOSName("Win"); }
    void setPhoneName() { ph.setPhoneName("Galaxy"); }
    void setPhonePrice() { ph.setPhonePrice(100); }
}

class A02ModelSettingInfo : public SettingInfo {
public:
    void setOSName(Q) { ph.setOSName("Linux"); }
    void setPhoneName() { ph.setPhoneName("Galaxy2"); }
    void setPhonePrice() { ph.setPhonePrice(110); }
}

class Director {
    void SetInfo(SettingInfo& setting) {
    	settings.SetInfo();
    }
};

int main()
{
    Director d;
    A01SettingInfo settings;
    d.SetInfo(settings);
    
    Phone ph = settings.result();
    ...;
}

위와 같이 구성이 된다면 새로운 모델이 추가될 경우 A03SettingInfo를 추가하지만 모두 상위 클래스인 Settings를 통해 접근하면 됩니다.

이처럼 Builder 패턴은 Director 클래스와 설정(구성)을 담당하는 Builder 클래스로 구성이 됩니다. Director 클래스에 설정을 위한 Builder 클래스를 넘겨주어 설정을 완료하고 최종적으로 설정된 결과물을 return 받는식으로 구성이 됩니다. Builder 패턴을 사용하면 객체를 한꺼번에 생성하는 것이 아닌 부분부분을 생성 후 결과를 얻어가는 방식이기 때문에 객체 생성 과정을 세밀하게 컨트롤할 수 있습니다.

 

728x90

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

C++ 프로토 타입 패턴  (0) 2021.05.08
C++ 팩토리 메소드 패턴  (0) 2021.05.08
C++ 추상 팩토리 패턴  (0) 2021.05.02
C++ 상속(Inheritance)  (0) 2020.05.08
C++ cout 자리수 지정하기  (0) 2020.02.28

+ Recent posts