데코레이터 패턴

주어진 상황 및 용도에 따라 어떤 객체에 책임을 덧붙이는 패턴으로 객체에 추가 요소를 동적으로 더 할 수 있다 / 서브클래스를 만들 때보다 훨씬 유연하게 기능을 확장 가능하다.

 

 

 

커피 주문 시스템

커피를 주문할 때 우유나 두유, 모카, 휘핑크림 등 다양한 토핑이들어가고 각각을 추가할 때 가격이 올라가기 때문에 이런 점을 고려하다보면 수 많은 클래스가 생성된다.

상속의 남용으로 하나의 기능을 추가하기 위해 필요 이상으로 많은 수의 클래스를 추가해야 하는 경우를 클래스 폭발 (Class Explosion) 또는 조합의 폭발 (Combinational Explosion) 문제 라고 한다.

 

 

음료수의 첨가물을 관리하기위해 Beverage를 다음과 같이 수정하였다.

 

이렇게 수정한 구조는 다음과 같은 문제점이 있다.

  • 첨가물 가격이 바뀔 때마다 기존 코드를 수정해야 한다.
  • 첨가물의 종류가 추가될수록 새로운 메서드를 추가해야하고 cost메서드도 수정해야한다.
  • 음료수에 특정 첨가물이 들어가면 안되는 경우 (아메리카노에 우유를 붓는다는 등)
  • 더블 샷 (휘핑크림 두번 등)

 

OCP (Open-Closed Principle) - 클래스는 확장에 열려 있어야 하지만 변경에는 닫혀 있어야 한다.

 

특정 음료(특정 원두)에서 시작하여 첨가물로 그 음료를 장식하기

데코레이터 패턴을 적용한 커피 시스템 구조

 

데코레이터가 적용된 예

자바 I/O

 

 

 

 

예시) 크리스마스 트리

#include <iostream>

using namespace std;


class ChristmasDecorator {
protected:
    string description;
public:
    virtual ~ChristmasDecorator() {};

    virtual string getDescription() = 0;
    virtual unsigned int cost() = 0;
};

class DeerModel : public ChristmasDecorator {
public:
    string getDescription() override {
        description = "사슴 모형";
        return description;
    }
    unsigned int cost() { return 100; }
};

class Tree : public ChristmasDecorator {
public:
    string getDescription() override {
        description = "트리";
        return description;
    }
    unsigned int cost() { return 50; }
};

class Garlands : public ChristmasDecorator {
public:
    string getDescription() override {
        description = "화환";
        return description;
    }
    unsigned int cost() { return 10; }
};


class MiniDecorator : public ChristmasDecorator {
protected:
    ChristmasDecorator *christmasdecorator;
public:
    virtual string getDescription() override = 0;
    virtual unsigned int cost() override = 0;

    ChristmasDecorator* getCurrentChristmasDecorator() { 
        return christmasdecorator; 
    }
};

class Bell : public MiniDecorator {
public:
    Bell (ChristmasDecorator* _christmasdecorator) {
        christmasdecorator = _christmasdecorator;
    }

    string getDescription() override {
        return christmasdecorator->getDescription() + " 벨 ";
    }
    unsigned int cost() override {
        christmasdecorator->cost() + 5;
    }
};

class Flower : public MiniDecorator {
public:
    Flower (ChristmasDecorator* _christmasdecorator) {
        christmasdecorator = _christmasdecorator;
    }

    string getDescription() override {
        return christmasdecorator->getDescription() + " 꽃 ";
    }
    unsigned int cost() override {
        christmasdecorator->cost() + 1;
    }
};

class Pinecone : public MiniDecorator {
public:
    Pinecone (ChristmasDecorator* _christmasdecorator) {
        christmasdecorator = _christmasdecorator;
    }

    string getDescription() override {
        return christmasdecorator->getDescription() + " 벨 ";
    }
    unsigned int cost() override {
        christmasdecorator->cost() + 10;
    }
};

class Baubles : public MiniDecorator {
public:
    Baubles (ChristmasDecorator* _christmasdecorator) {
        christmasdecorator = _christmasdecorator;
    }

    string getDescription() override {
        return christmasdecorator->getDescription() + " 장식볼 ";
    }
    unsigned int cost() override {
        christmasdecorator->cost() + 4;
    }
};

class TreeTopper : public MiniDecorator {
public:
    TreeTopper (ChristmasDecorator* _christmasdecorator) {
        christmasdecorator = _christmasdecorator;
    }
    
    string getDescription() override {
        return christmasdecorator->getDescription() + " 트리 헤드 장식 ";
    }
    unsigned int cost() override {
        christmasdecorator->cost() + 25;
    }
};


class FairyLights : public MiniDecorator {
public:
    FairyLights (ChristmasDecorator* _christmasdecorator) {
        christmasdecorator = _christmasdecorator;
    }

    string getDescription() override {
        return christmasdecorator->getDescription() + " 꼬마 전구 ";
    }
    unsigned int cost() override {
        christmasdecorator->cost() + 10;
    }
};



int main() {
    ChristmasDecorator* christmasTree = new Tree{};
    ChristmasDecorator* treeTopper = new TreeTopper{christmasTree};
    ChristmasDecorator* fairyLights = new FairyLights{treeTopper};

    cout << fairyLights->cost() << endl;
    cout << fairyLights->getDescription() << endl;
}

 

'디자인 패턴' 카테고리의 다른 글

어댑터 패턴 (Adaptor pattern)  (0) 2023.04.30
커맨드 패턴 (Command Pattern)  (0) 2023.04.23
싱글톤 패턴 (Singleton Pattern)  (0) 2023.04.16
옵저버 패턴  (0) 2023.03.26
전략 패턴 (Strategy Pattern)  (0) 2023.03.20

+ Recent posts