일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 팩터리 메서드
- 빌더
- 추상 팩터리
- 모던C++디자인패턴
- 싱글턴 패턴
- 프로토타입 패턴
- 동적 데코레이터
- 컴포지트 빌더
- 팩터리 패턴
- 싱글톤
- 프로토타입
- 그루비 스타일 빌더
- 데커레이터 패턴
- 데커레이터
- 싱글톤 패턴
- 빌더 패턴
- 단순한 빌더
- 싱글턴
- 흐름식 빌더
- 브릿지 패턴
- 함수형 팩터리
- 디자인패턴
- 디자인 패턴
- 컴포지트
- 동적 데커레이터
- 팩터리
- 브릿지
- 컴포지트 패턴
- 프로토타입 중복처리
- 내부 팩터리
- Today
- Total
GGym's Practice Notes
2-1. 빌더_빌더 패턴 본문
빌더 패턴은 생성이 까다로운 객체를 쉽게 처리하기 위한 패턴이다.
즉, 생성자 호출 코드 단 한 줄로 생성할 수 없는 객체를 다룬다.
- 시나리오
웹 페이지를 그리기위한 컴포넌트들을 생성해야 한다고 할때
각각의 HtmlElement를 생성하는 과정을 간소화 한다.
객체 지향 스타일을 채용하여 HtmlElement 클래스를 정의하여 각 html 태그에 대한 정보를 저장한다.
struct HtmlElement{
string name;
string text;
vector<HtmlElement> elements;
string str(int indent = 0) const{
// 컨텐츠를 양식에 맞추어 출력
}
HtmlElement(){}
HtmlElement(const string& name, const string& text)
: name(name), text(text){}
};
이러한 접근 방법을 활용하여 출력 양식이 좀 더 드러나도록 리스트를 생성할 수 있다.
string words[] = {"hello", "world"};
HtmlElement list{"ul", ""};
for(auto w : words)
list.elements.emplace_back(HtmlElement{"li", w});
printf(list.str().c_str());
양식을 제어하기가 좀 더 쉽고 목적하는 출력을 할 수 있지만 각각의 HtmlElement를 생성하는 작업이 그렇게 편리하다고 볼 수 없다.
- 단순한 빌더
빌더 패턴은 단순하게 개별 객체의 생성을 별도의 다른 클래스에 위임한다.
struct HtmlBuilder{
HtmlElement root;
HtmlBuilder(string root_name) {root.name = root_name;}
void add_child(string child_name, string child_text){
HtmlElement e{child_name, child_text};
root.elements.emplace_back(e);
}
string str() {return root.str();}
};
HtmlBuilder는 HTML 구성요소의 생성만을 전담하는 클래스이다.
add_child()는 현재 요소에 자식요소를 추가하는 목적으로 사용된다.
이 클래스는 출력부분이 아래와 같이 사용된다.
HtmlBuilder builder{"ul"};
builder.add_child("li", "hello");
builder.add_child("li", "world");
cout << builder.str() << endl;
- 흐름식 빌더
다음과 같이 자기 자신을 리턴하도록 수정한다.
HtmlBuilder& add_child(string child_name, string child_text){
HtmlElement e{child_name, child_text};
root.elements.emplace_back(e);
return *this;
}
빌더 자기자신이 리턴되기 때문에 다음과 같이 메서드들이 꼬리를 무는 호출이 가능하다.
이러한 형태로 호출하는 것을 흐름식 인터페이스라고 부른다.
HtmlBuilder builder{"ul"};
builder.add_child("li", "hello").add_child("li", "world");
cout << builder.str() << endl;
리턴을 포인터로 할지 참조로 할지는 개발자의 마음대로다.
- 의도 알려주기
사용자가 빌더 클래스를 사용해야 한다는 것을 알게하기 위해서 빌더를 사용하지 않으면 객체 생성을 불가능하게 한다.
(모든 생성자를 protected로 숨겨서 객체생성을 불가능하게 한다.)
이 접근 방법은 두가지 축으로 이루어진다. 첫번째로 모든 생성자를 숨겨서 사용자가 접근할 수 없게 하는 것이다. 두번째로 생성자를 숨긴 대신 HtmlElement 자체에 팩터리 메서드를 두어 빌더를 생성할 수 있게 한다. 팩터리 메서드 역시 static 메서드로 만든다.
- 전체 코드
#include<iostream>
#include<sstream>
#include<vector>
#include<string>
#include<memory>
using namespace std;
struct HtmlBuilder;
class HtmlElement{
public:
string name;
string text;
vector<HtmlElement> elements;
const size_t indent_size = 2;
string str(int indent = 0) const{
ostringstream oss;
string i(indent_size * indent, ' ');
oss << i << "<" << name << ">" << endl;
if (text.size() > 0)
oss << string(indent_size*(indent + 1), ' ') << text << endl;
for (const auto& e : elements)
oss << e.str(indent + 1);
oss << i << "</" << name << ">" << endl;
return oss.str();
}
static unique_ptr<HtmlBuilder> build(const string& root_name){
return make_unique<HtmlBuilder>(root_name);
}
friend HtmlBuilder;
protected:
HtmlElement(){}
HtmlElement(const string& name, const string& text)
: name(name), text(text){}
int num = 10;
};
class HtmlBuilder{
public:
HtmlBuilder(string root_name){
root.name = root_name;
}
HtmlBuilder* add_child(string child_name, string child_text){
HtmlElement e{child_name, child_text};
root.elements.emplace_back(e);
return this;
}
string str() { return root.str();}
operator HtmlElement() const {return root;}
HtmlElement root;
};
int main(){
auto builder = HtmlElement::build("ul")
->add_child("li","Hello")->add_child("li","World");
cout << builder->str() << endl;
return 0;
}
'Design Pattern > Modern C++ 디자인패턴' 카테고리의 다른 글
3-2. 팩터리_추상 팩터리/함수형 팩터리 (0) | 2020.04.02 |
---|---|
3-1. 팩터리_팩터리 메서드/팩터리/내부 팩터리 (0) | 2020.04.02 |
2-3. 빌더_컴포지트 빌더 (0) | 2020.03.31 |
2-2. 빌더_그루비-스타일 (0) | 2020.03.31 |
1. SOLID 디자인 원칙 (0) | 2020.03.24 |