본문 바로가기
Programming/디자인 패턴

데코레이터 패턴 Decorator Pattern

by Bam_t 2021. 9. 2.
728x90

이번에 소개할 패턴은 데코레이터 패턴입니다. 데코레이터 패턴은 Structural Pattern에 속합니다.


1. 데코레이터 패턴 소개

어디선가 한 번쯤은 "데코레이션"이라는 말을 들어봤을 것입니다. 케이크 위에 과일이나 장식을 얹는 것, 음료에 가니쉬나 다양한 첨가물을 넣는 것들을 우리는 데코레이션 이라고 합니다. 이처럼 한 객체 위에 기능들을 입혀서 사용 목적에 걸맞는 객체로 만드는 것을 데코레이션 패턴이라고 합니다.

예를들면, 케이크 빵위에 생크림을 바르면 생크림 케이크, 초코를 바르면 초코 케이크가 되고, 같은 생크림 케이크 라도 과일을 올릴 수도 있고, 초코를 올릴 수도 있죠. 심지어는 같은 장식(기능)이라도 케이크 빵대신 베이글을 넣을 수도 있습니다. 이처럼 각기 다른 베이스를 가지고 장식을 통해 객체를 목적에 맞게 완성시키기 위한 패턴입니다. 

 

 

2. 데코레이터 패턴 구현

커스텀 케이크 가게를 예시로 들며 간단하게 구현해보겠습니다.

 

우선 케이크 빵의 종류를 결정하는 Cakesheet 클래스 입니다. 빵의 종류에 따라 이름이 달라질 것이므로 추상클래스로 구현했습니다.

package Decorator;

public abstract class Cakesheet {
	//케이크의 종류를 설명하는 description
    String description = "케이크시트";

    public String getDescription() {
        return description;
    }

	//케이크의 가격을 계산할 cost 메소드
    public abstract long cost();
}

 

이번에는 장식을 담은 Decroation 클래스입니다. 케이크의 설명에 장식이름이 추가될 것이므로 Cakesheet를 상속해서 설명 설정 메소드인 getDescription을 공유하고 있습니다.

package Decorator;

public abstract class Decoration extends Cakesheet {
    public abstract String getDescription();
}

 

케이크 빵을 결정하는 객체입니다 시폰과 스폰지 두 종류를 만들었습니다.

package Decorator;

public class Chiffon extends Cakesheet {
	//객체 생성자에서 케이크 이름 명시
    public Chiffon() {
        description = "시폰 케이크";
    }

    @Override
    public long cost() {
        return 7000;
    }
}
package Decorator;

public class Sponge extends Cakesheet {
    public Sponge() {
        description = "스폰지 케이크";
    }

    @Override
    public long cost() {
        return 5000;
    }
}

 

이번에는 데코레이션 부분입니다.

package Decorator;

public class WhippingCream extends Decoration {
    Cakesheet cakesheet;

	//베이스로 설정한 케이크시트를 가져와서 장식하는데 이용합니다.
    public WhippingCream(Cakesheet cakesheet) {
        this.cakesheet = cakesheet;
    }

	//케이크 베이스 가격에 장식의 가격을 더합니다.
    @Override
    public long cost() {
        return cakesheet.cost() + 1000;
    }

	//케이크 이름에 장식 이름을 더해줍니다.
    @Override
    public String getDescription() {
        return "생크림 " + cakesheet.getDescription();
    }
}
package Decorator;

public class Chocolate extends Decoration {
    Cakesheet cakesheet;

    public Chocolate(Cakesheet cakesheet) {
        this.cakesheet = cakesheet;
    }

    @Override
    public long cost() {
        return cakesheet.cost() + 1500;
    }

    @Override
    public String getDescription() {
        return "초콜릿 " + cakesheet.getDescription();
    }
}
package Decorator;

public class Mocha extends Decoration {
    Cakesheet cakesheet;

    public Mocha(Cakesheet cakesheet) {
        this.cakesheet = cakesheet;
    }

    @Override
    public long cost() {
        return cakesheet.cost() + 2000;
    }

    @Override
    public String getDescription() {
        return "모카 " + cakesheet.getDescription();
    }
}

 

이제 main메소드가 담긴 케이크 가게 클래스입니다.

package Decorator;

public class CustomCakeShop {
    public static void main(String[] args) {
        System.out.println("==1번 손님==");
        Cakesheet cake1 = new Sponge();
        System.out.println(cake1.getDescription() + "는 " + cake1.cost() + "원");
        System.out.println("----------------");

        System.out.println("==2번 손님==");
        Cakesheet cake2 = new Sponge();
        cake2 = new WhippingCream(cake2);
        System.out.println(cake2.getDescription() + "는 " + cake2.cost() + "원");
        System.out.println("----------------");

        System.out.println("==3번 손님==");
        Cakesheet cake3 = new Sponge();
        cake3 = new WhippingCream(cake3);
        cake3 = new Mocha(cake3);
        System.out.println(cake3.getDescription() + "는 " + cake3.cost() + "원");
        System.out.println("----------------");

        System.out.println("==4번 손님==");
        Cakesheet cake4 = new Chiffon();
        cake4 = new WhippingCream(cake4);
        cake4 = new Mocha(cake4);
        System.out.println(cake4.getDescription() + "는 " + cake4.cost() + "원");
        System.out.println("----------------");
    }
}

전체 코드를 살펴봤으니 이제 실행결과를 볼까요?

이처럼 같은 케이크 시트에서 시작하더라도 장식에 따라 다른 결과를 보여주고있고, 같은 장식이라도 다른 케이크 시트에 따라서도 종류가 바뀜을 볼 수 있습니다.

 

이때 객체 생성과정에서 장식 -> 케이크 시트 순서로 생성하면 어떻게 되는가?하는 의문이 생길 수도 있는데요. 그것은 장식 클래스들의 생성자에 케이크 시트가 존재해야 하는 조건이 달려있으니 장식부터 하게 된다면 오류를 내게 됩니다.

 

보셨듯이 같은 객체들을 가지고 다양한 조합의 결과를 나타냈습니다. 지금까지 객체의 확장을 자유롭게 만들어주는 패턴인 데코레이터 패턴이었습니다.


https://github.com/Bam-j/DesignPattern/tree/master/src/Decorator

 

GitHub - Bam-j/DesignPattern: 디자인 패턴 블로그 기재

디자인 패턴 블로그 기재. Contribute to Bam-j/DesignPattern development by creating an account on GitHub.

github.com

 

728x90

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

커맨드 패턴 Command Pattern  (0) 2021.09.15
싱글턴 패턴 Singleton Pattern  (0) 2021.09.13
팩토리 패턴 Factory Pattern  (0) 2021.09.09
옵저버 패턴 Observer Pattern  (0) 2021.09.01
디자인 패턴  (0) 2021.08.30

댓글