일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 우아한테크코스
- 자바
- 인프런
- 프로그래머스
- 알고리즘
- math
- 회고
- 인강리뷰
- 인코딩
- Head First Design Pattern
- study
- 독서
- javascript
- 오라클
- 공부
- 카카오톡1차
- JPA
- 독서리뷰
- 매핑
- Java
- 람다
- 에러
- 후기
- spring
- Singleton
- Design Pattern
- Eclipse
- 디자인패턴
- Oracle
- 이펙티브자바
- Today
- Total
Lee's Grow up
[디자인패턴/Design Pattern] Decorator Pattern / 데코레이터 패턴 본문
관련 내용은 [자바 언어로 배우는 디자인 패턴 입문]
,[Head First Design Pattern]
의 내용을 참고해서 정리한 내용입니다. 잘못된 부분은 댓글로 피드백 주시면 감사하겠습니다.
1. Docorator 패턴이란?
객체에 추가적인 요건을 동적으로 첨가할때 사용하는 방식으로, 서브클래스를 만드는 것을 통해서 기능을 유연하게 확장할 수 있는 방법을 제공합니다.
2. Decorator 패턴의 등장인물
- Component
- 기능을 추가할 때 핵심이 되는 역할로, 해당 기능의 인터페이스(API)만을 결정합니다.
- ConcreteCompoent
- Component를 실제로 구현하는 역할입니다.
- Decorator(장식자)
- Component와 동일한 인터페이스(API)를 가지며, 구체적인 장식자의 Component 역할을 합니다.
- ConcreteDecorator(구체적인 장식자)
- Decorator를 시렞로 구현하는 역할입니다.
2-1. Decorator 패턴의 클래스 다이어그램
3. 예제
여러분이 스타OO과 같은 음료회사의 주문시스템을 만들어야 하는 상황이 생겼다고 가정했을 때, 음료라는 큰 슈퍼클래스를 두고 음료들을 서브클래스로 두어서 구현을 하려고 할 것입니다.
그런데 음료의 갯수가 너무 많아진다면? 또한 휘핑크림 추가나 우유 추가등 첨가물에 따라서 동작이나 가격이 달라진다면? 엄청나게 많은 클래스가 필요할것이고, 휘핑크림의 가격이 변동되면 수정해야 될 클래스들도 상당할 것이다.
3-1. 예제 클래스 다이어그램
이와 같은 상황에 여러분들은 공통되는 부분을 추출하고자 첨가물인 밀크, 휘핑크림등을 슈퍼클래스의 구성으로 가지면 밀크가 들어간 에스프레소, 휘핑크림이 들어간 에스프레소 등을 하나의 에스프레소 클래스로 줄일 수 있지 않을까라는 생각이 들 수도 있습니다.
3-2. 첨가물을 구성으로 가지는 슈퍼 클래스
public abstract class Beverage {
private Milk milk ;
private Whip whip;
// 기타 필요한 필드 및 생성자는 생략
public void addMilk() {
// 우유 추가 동작 구현
}
// milk 관련 메소드 게터세터 등등
// 나머지 메소드도 생략
}
대충 슈퍼클래스가 위와 같은 방식으로 정의되어 있을 때, 첨가물을 구성으로 사용하여 클래스 개수도 줄이는 등 괜찮아 보일 수 있지만 아직도 아래와 같은 문제점이 존재합니다.
3-2 클래스의 문제점
- 첨가물에 대한 수정이 있을 경우 super 클래스의 수정이 필요 ( 추가, 수정, 삭제 등 )
- 새로운 클래스가 우유가 들어가면 안되는 경우 서브클래스에서
addMilk()
메소드가 동작 안하도록 추가 구현 필요 - 우유를 2번 추가하는 동작이 필요하면
doubleAddMilk()
메소드가 필요
등과 같은 여러 문제가 아직 발생합니다. 이렇게 동적으로 객체에 요건을 추가할 상황이 많을 경우 데코레이터 패턴을 사용합니다.
4. Decorator 패턴을 사용한 해결
4-1. 예제에 사용 될 클래스 다이어그램
4-2. BeverageComponent 클래스
Compoent 역할로써 전체의 핵심 역할로 인터페이스(API)를 정의하는 클래스입니다. 여기서 전체 구현하는 클래스들의 '형식'을 정해줍니다. 사실상 좀 더 발전된 디자인의 방식으로는 해당 클래스도 abstract가 아닌 interface로 '형식'만 정의해주는 방식이 가장 이상적이지만
예제에서는 기존에 BeverageComponent
라는 추상클래스가 존재할 때 변경방법을 소개하는 방향이여서 추상 클래스를 써야 하는 상황이라면 그냥 추상클래스로 구성하는게 더 나을수도 있습니다. 즉 구현하는 시점에 좀 더 비용이 저렴한 방식을 사용하면 됩니다.
public abstract class BeverageComponent {
protected String name;
public String getName() {
return name;
}
public abstract int cost();
}
4-3. CondimentDecorator 클래스
Decorator
의 역할로, Compoent
역할인 BeverageComponent
를 상속받으며, ConcreteDecorator
의 Compoent
를 역할을 수행합니다.
public abstract class CondimentDecorator extends BeverageComponent {
public abstract String getName();
}
4-4. Hazelnut 클래스
ConcreteDecorator
의 역할로 CondimentDecorator
를 상속받아 내용을 정의해줍니다.
핵심은 필드로 BeverageComponent
클래스를 가지며, 확장의 대상이 될 객체를 참조시킵니다.
나머지 Milk
, Mocha
도 필요에 따라 정의해주시면 됩니다.
public class Hazelnut extends CondimentDecorator {
BeverageComponent beverage;
public Hazelnut(BeverageComponent beverage) {
this.beverage = beverage;
}
@Override
public String getName() {
return "헤이즐넛 시럽 추가, " + beverage.getName() ;
}
@Override
public int cost() {
return 500 + beverage.cost();
}
}
4-5. Main 클래스
public class Main {
public static void main(String[] args) {
BeverageComponent beverage = new Americano();
System.out.println(beverage.getName() +" 가격 : " + beverage.cost());
BeverageComponent beverage2 = new Americano();
beverage2 = new Mocha(beverage2);
beverage2 = new Hazelnut(beverage2);
System.out.println(beverage2.getName() +" 가격 : " + beverage2.cost());
}
}
beverage2
를 보시면 생성자를 통해 확장시키고 싶은 객체를 참조시키며 자신으로 감싸는 모습이 보입니다.
이렇게 확장이 필요할 경우 원하는 만큼 객체를 감싸면서 객체를 확장해 갈 수 있는 방식입니다.
4-5 실행결과
아메리카노 가격 : 2000
헤이즐넛 시럽 추가, 모카 추가, 아메리카노 가격 : 3300
우유 추가 , 아메리카노 가격 : 3500
왜 사용할까?
- 추가 첨가물(휘핑크림)인
Whip
클래스가 추가 된다고 가정했을 때, 그냥Whip
클래스를 생성해주고,CondimentDecorator
클래스를 상속받아 내용만 정의해주면 기존 코드에 수정없이 클라이언트는Whip
첨가물을 사용할 수 있게 됩니다.
5. 관련 패턴
Adapter
패턴 : Decorator 패턴은 내용을 변경없이 장식을 추가하는 패턴이고, 해당 패턴은 다른 두개의 인터페이스를 연결해줍니다. linkStrategy
패턴 : 알고리즘 자체를 변경해서 기능을 확장이 아닌 변경합니다. link
6. 비교하기
디자인 패턴을 배우다 보니까 Adapter , Decorator, Facade 가 얼핏 보면 비슷하다고 느낌이 들어서 차이점을 정리합니다.
'PROGRAMMING > 디자인패턴' 카테고리의 다른 글
[디자인패턴/Design Pattern] Composite Pattern / 컴포지트 패턴 (0) | 2019.12.17 |
---|---|
[디자인패턴/Design Pattern] Facade Pattern / 퍼사드 패턴 (0) | 2019.12.16 |
[디자인패턴/Design Pattern] Observer 패턴 / 관찰자 패턴 / Publish-Subscribe 패턴 (0) | 2019.12.11 |
[디자인패턴/Design Pattern] Strategy 패턴 / 전략 패턴 (0) | 2019.12.11 |
[디자인패턴/Design Patter] Prototype 패턴 프로토타입 패턴 (0) | 2019.11.27 |