2020년 7월 6일 월요일

GOF Design Pattern - Builder





설명


 생성용 인터페이스 Builder 가 있고, 원하는 단계의 종류별로 Concrete Builder 를 만들어서

 객체의 생성 과정과 표현방법이 분리되어 있음. 

 생성 단계별로 있다는게 중요함.


 Abstract Factory 는 유사한 클래스 간의 생성, 수정 등의 인터페이스를 갖게하는 거고, 

 Builder 는 복잡한 객체의 단계별 생성에 중점을 두는 것이 차이.



예제 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MazeBuilder
{
public:
    // 굳이 추상클래스일 필요는 없음
    virtual void BuildMaze() = 0;
    virtual void BuildRoom(int n) = 0;
    virtual void BuildDoor(int from, int to) = 0;
    virtual class Maze* GetMaze() = 0;
 
protected:
    MazeBuilder() = default;
 
private:
    class Maze* _maze_cur;
};
cs


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
31
32
33
34
35
36
37
38
39
40
class StandardMazeBuilder : public MazeBuilder
{
public:
    StandardMazeBuilder() : _currentMaze(nullptr) {}
 
    virtual void BuildMaze()
    {
        if (_currentMaze) delete _currentMaze;
        _currentMaze = new Maze();
    }
    virtual void BuildRoom(int n) 
    {
        Room* r = new Room(n);
        
        r->SetSide(North, new Wall());
        r->SetSide(South, new Wall());
        r->SetSide(East, new Wall());
        r->SetSide(West, new Wall());
 
        _currentMaze->AddRoom(new Room(n));
    }
 
    virtual void BuildDoor(int from, int to)
    {
        Room* r1 = _currentMaze->RoomNo(from);
        Room* r2 = _currentMaze->RoomNo(to);
        Door* d = new Door(r1, r2);
 
        r1->SetSide(CommonWall(r1, r2), d);
        r2->SetSide(CommonWall(r2, r1), d);
    }
 
    virtual Maze* GetMaze() { return _currentMaze; }
 
private:
    Direction CommonWall(Room* r1, Room* r2) { return South; }
    // 바둑판식 방이라면 두개의 방이 인접한 경우 r1 에서의 r2 의 방향을 리턴한다.
 
    Maze* _currentMaze;
};
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class CountingMazeBuilder : public MazeBuilder
{
public:
    CountingMazeBuilder() : _rooms(0), _doors(0) {}
 
    virtual void BuildMaze();
    virtual void BuildRoom(int) { _rooms++; }
    virtual void BuildDoor(intint) { _doors++; }
    virtual void AddWall(int, Direction);
 
    void GetCounts(int& r, int& d) const { r = _rooms; d = _doors; }
 
private:
    int _doors;
    int _rooms;
};
cs

1
2
3
4
5
6
7
8
9
10
11
Maze* MazeGame::CreateMaze()
{
    m_builder->BuildMaze();
    m_builder->BuildRoom(1);
    m_builder->BuildRoom(2);
    m_builder->BuildDoor(12);
 
    m_mazes.push_back(m_builder->GetMaze());
 
    return m_builder->GetMaze();
}
cs


Maze 가 Wall, Room, Door 로 구성되어 있다고 하면,
Maze 를 만들고 안에 Wall, Room, Door 를 추가하기 위해
Builder 를 통해서만 가능하게 구현하는 것.

단계별 생성 절차를 CreateMaze() 처럼 Director 가 지시하게 됨.
이게 CountingMazeBuilder 를 쓰더라도 생성 절차 인터페이스는 통일적임.

Builder 가 생성 관련 제약을 해결해주기 때문에
Maze, Wall, Room, Door 의 객체들이 더욱 간단해짐.



추가 설명

Abstract Factory 는 상속 등을 통한 유사한 클래스 간의 생성, 수정의 인터페이스 통일이 목적이고, Builder 는 다양한 종류의 단계별 생성 간의 인터페이스 통일이 목적인 것이라 초점이 다른 거임.


댓글 없음:

댓글 쓰기

List