2. 스타버즈 커피...
• 다양한 음료를 판다.
• Beverage 추상클래스를 기반으로 다양한 형태의 음료를 서브 클래스로.
• cost() 함수를 추상메소드로 가지고 있으며, 서브 클래스에서 오버라이브 하는
방식으로 음료의 가격을 각 서브 클래스에서 구현하는 구조.
2
7. 방금 전 단계에서의 문제는?
토핑의 가격이 바뀔때 마다 추상클래스에서 해당 부분 수정
토핑의 종류가 추가시, 새 변수 및 새 함수, 추상클래스의 cost() 함수 변경
우유, 휘핑 크림이 안 들어가는 티(tea)가 추가된다면, Tea 서브 클래스는
여전히 관련 함수는 상속 받는 문제가 있음(1장 Strategy Pattern 에서도
같은 문제 있었음.)
7
8. 상속과 구성에 대해서
• 상속을 사용시 문제점
- 객체의 행동이 컴파일 시점에서 완전히 결정이 되고 런타임 시점에
특정객체의 행동을 변경할 수 없는 문제가 있다.
• 구성(Composition)을 이용한 객체의 유연성 확보
- 객체의 행동을 런타임 시점에도 변경할 수 있다.
- 객체를 동적으로 구성하면, 기존의 코드를 수정하는 대신에 새롭게
추가할 수 있다.
8
10. 데코레이터 패턴을 쓴다면..
• 스타버즈의 예..
• 특정 음료에서 시작해서 토핑으로 그 음료를 장식하는 형태로 진행하겠다.
1. 음료 객체를 가져온다. (DarkRoast 객체를 가져와서)
2. 토핑 객체로 장식한다. (Mocha, Whip 객체로 장식을 한다.)
3. cost() 메소드를 호출한다. 이때 토핑의 가격 계산은 토핑 객체가
수행한다.
10
11. 데코레이터를 써서 음료 주문을 완성하는 방법
“다크 로스트 커피에 모카와 휘핑크림 추가”
cost() cost() cost()
Whip Mocha DarkRost
Mocha, Whip 은 데코레이터 객체
- 데코레이터 객체의 형식은 객체가 장식하고 있는 객체를 반영한다.
= DarkRoast와 같은 형식이다.(Beverage)
11
12. 데코레이터를 써서 음료 주문을 완성하는 방법
“다크 로스트 커피에 모카와 휘핑크림 추가”
cost() cost() cost()
Whip Mocha DarkRost
cost() 함수의 호출은 가장 바같쪽의 Whip 의 cost() 부터 호출하면 된다.
호출하게 되면 해당 객체가 장식하고 있는 객체에게 가격 계산을 위임하고
계산이 끝나면 결과를 리턴한다.
12
13. 정리해 보면..
• 데코레이터의 슈퍼 클래스는 자신이 장식하고 있는 객체의 슈퍼클래스와
같다.
- Whip의 슈퍼 클래스 = Mocha의 슈퍼클래스 = DarkRoast의 슈퍼클래스
• 한 객체를 여러 개의 데코레이터로 감쌀 수 있습니다.
• 데코레이터는 자신이 감싸고 있는 객체와 같은 슈퍼 클래스를 가지고 있기
때문에 원래 싸여져 있는 객체가 들어갈 자리에 데코레이터 객체를 넣어도
된다.
- Whip클래스가 감싸고 있는 것이
DarkRoast가 아닌 Mocha 데코레이터 클래스
13
14. 정리해 보면..
• 데코레이터는 자신이 장식하고 있는 객체에 어떤 행동을 위임하는 것
외에 원하는 추가적인 작업을 수행할 수 있다.
• 객체는 언제든지 감쌀 수 있기 때문에 실행 중에 필요한 데코레이터를
마음대로 적용할 수 있다.
14
15. 데코레이터 패턴의 정의
• 객체에 추가적인 요건을 동적으로 첨가하는 패턴으로 데코레이터는
서브 클래스를 만드는 것을 통해서 기능을 유연하게 확장할수 있는
방법을 제공한다.
15
17. 데코레이터가 적용된 예 : 자바 I/O
LineNumber Buffered
InputStream File
InputStream
InputStream
FileInputStream이 여기서는 포장될 음료이고,
BufferedInputStream, LineNumberInputStream이 구상 데코레이터이다.
17
18. 자바I/O와 데코레이터 패턴
추상 구성요소
추상 데코레이터
데코레이터
단점 : 데코레이터 패턴을 이용한 디자인을 하다보면, 클래스가 많아 질수가 있다.
18
19. 핵심정리
• 상속을 통해서 확장을 할수 있지만, 디자인 측면에서 별로 좋지 않다.
• 기존 코드를 수정하지 않고 행동을 확장하는 방법이 필요하다.
• 구성과 위임을 통해서 실행중에 새로운 행동을 추가 할수 있다.
• 데코레이터 패턴에서는 구성요소를 감싸주는 데코레이터를 사용한다.
• 데코레이터 클래스의 형식은 그 클래스가 감싸고 있는 클래스의 형식을 반영한다.
• 구성요소를 감싸는 데코레이터의 개수에는 제한이 없다.
• 구성요소의 클라이언트 입장에서는 데코레이터의 존재를 알 수가 없다.
클라이언트에서 구성 요소의 구체적인 형식에 의존하게 되는 경우는 예외이다.
• 데코레이터 패턴을 사용하면 자잘한 객체들이 매우 많이 추가될수 있고 너무 많이
사용하면 코드가 필요 이상으로 복잡해 질 수도 있다.
19
20. 137p 연습문제
스타버즈에서 사이즈 개념을 도입한다.
전체 커피 클래스에 영향을 미치니까 Beverage에 get, set 함수 추가
사이즈에 따라 첨가물 가격도 다르게 받을 예정, 어떻게 고쳐야 하는가?
20
21. 현재 스타버즈의 문제점..
• 클래스 간의 결합이 강한 결합의 상태이다.
• 추상 클래스를 쓰는 것 보다는 인터페이스를 사용해서 구현하는
방식이 좀더 느슨한 결합(loosed-coupling)을 유도한다.
• 추상 클래스를 걷어내고, 인터페이스로 바꾼다.
21