26
Design Patterns Study 2. Decorator pattern

Design patterns 스터디 -Decorator 패턴

Embed Size (px)

Citation preview

Page 1: Design patterns 스터디 -Decorator 패턴

Design Patterns Study2. Decorator pattern

Page 2: Design patterns 스터디 -Decorator 패턴

본 PPT는 Design Patterns Study를 위해 작성되었습니다.

Study에 사용한 교재는 한빛미디어에서 나온 Head First Design Patterns을 사용하였습니다.

예시로 사용된 간단한 코드들은 https://github.com/doubleh777/DesignPatternsStudy.git에서 다운 받으 실 수 있습니다.

그리고 1989. 2. 6, 27년 전 오늘 태어난 김혜원 양 생일 축하합니다!!

Written by NHN NEXT 2기 조현호 For study with NHN NEXT 2기 조현호 서울시립대 이희태

Page 3: Design patterns 스터디 -Decorator 패턴

공부를 위해 간단한 시나리오를 생각해봅시다.

스타벅스에서 커피 정보를 관리하는 시스템을 만들고자 합니다.

객체 지향의 꽃은 상속이라는 말을 많이들 하던데 상속으로 만들면 되겠지?

Page 4: Design patterns 스터디 -Decorator 패턴

Beveragedescription

getDescription() cost()

//기타 메소드

HouseBlend

cost()

DarkRoast

cost()

Decaf

cost()

Espresso

cost()

Beverage 클래스를 상속받아 여러 커피들 객체를 만듭니다.

cost는 커피마다 다르니 오버라이딩 해줘야겠죠.

Page 5: Design patterns 스터디 -Decorator 패턴

물론 문제가 있죠.

기억 나시나요?

디자인 법칙

상속보다는 구성을 활용한다.

Page 6: Design patterns 스터디 -Decorator 패턴

Beveragedescription

getDescription() cost()

//기타 메소드

HouseBlend

cost()

DarkRoast

cost()

Decaf

cost()

Espresso

cost()

상속을 이용하면 이렇게… ….

클래스 개수가 폭발적으로 늘어날 수 밖에 없죠.

EspressoWith SteamedMilkAnd

Mocha

cost()

DecafWithSoy

cost()

DecafWithMocha

cost()

DarkRoastWith Mocha

cost()

EspressoWith WhipAndSoay

cost()DarkRoastWith

Soay

cost()

HouseBlendWith WhipAndSoay

cost()

HouseBlendWith Soy

cost()

장난하냐!!!

Page 7: Design patterns 스터디 -Decorator 패턴

인스턴스 변수하고 상속을 이용해서 추가사항을 관리하면 안될까요?

Page 8: Design patterns 스터디 -Decorator 패턴

HouseBlend

cost()

DarkRoast

cost()

Decaf

cost()

Espresso

cost()

Beveragedescription

milk soy

getDescription() cost()

hasMilk() setMilk() hasSoy() setSoy

hasMocha() setMocha()

이렇게 말이죠.

이렇게 하면 클래스 5개로

해결 할 수 있겠군요.

Page 9: Design patterns 스터디 -Decorator 패턴

앞서 말했다시피 우린 여전히 분명 지난시간 배웠던 디자인 원칙을 어겼습니다.

그런데 과연 문제가 없을까요?

Page 10: Design patterns 스터디 -Decorator 패턴

고객이 더블모카를 주문한다면 어떡하죠? 방법이 없군요…

첨가물의 종류가 추가 될때 마다 새로운 메소드를 추가해야겠군요. 뿐만 아니라 슈퍼클래스의 cost()메소드도 고쳐야겠고요.

커피가 아닌 새로운 음료를 출시 할 수도 있겠죠? 그러면 이런 음료들도 커피에만 들어가는 재료들을 모두 상속받아야 할텐데… 과연 이게 합리적일까요?

Page 11: Design patterns 스터디 -Decorator 패턴

이쯤에서 중요한 디자인 원칙 하나를 살펴봅시다.

Page 12: Design patterns 스터디 -Decorator 패턴

디자인 원칙

클래스는 확장에 대해서는 열려 있어야 하지만 코드 변경에 대해서는 닫혀 있어야 한다.

(Open-Closed Principle)

Page 13: Design patterns 스터디 -Decorator 패턴

그래서 소개합니다.

데코레이터 패턴!

Page 14: Design patterns 스터디 -Decorator 패턴

Beveragedescription

getDescription() cost()

//기타 메소드

HouseBlend

cost()DarkRoast

cost()Decaf

cost()Espresso

cost()

Decorator

getDiscription()

Milk

getDiscription()

Mocha

getDiscription()

Soy

getDiscription()

이런 식으로 설계하는 겁니다.

한번 살펴볼까요.

Page 15: Design patterns 스터디 -Decorator 패턴

Beveragedescription

getDescription() cost()

//기타 메소드

HouseBlend

cost()DarkRoast

cost()Decaf

cost()Espresso

cost()

Decorator

getDiscription()

Milk

getDiscription() cost()

Mocha

getDiscription() cost()

Soy

getDiscription() cost()

먼저 Beverage클래스를 상속하여 핵심 요소

(여기서는 에스프레소 같은 커피들이 되겠죠) 클래스를 만듭니다.

Page 16: Design patterns 스터디 -Decorator 패턴

Beveragedescription

getDescription() cost()

//기타 메소드

HouseBlend

cost()DarkRoast

cost()Decaf

cost()Espresso

cost()

Decorator

getDiscription()

Milk

getDiscription() cost()

Mocha

getDiscription() cost()

Soy

getDiscription() cost()

그리고 Beverage를 상속받는 Decorator라는 추상 클래스를 만들고,

데코레이터 아래에 첨가물을 하나씩 추가하는거죠!!!

Page 17: Design patterns 스터디 -Decorator 패턴

엥?? 왜 이렇게 하는거야??

이게 무슨 뜻인지 잘 이해가 안가…

Page 18: Design patterns 스터디 -Decorator 패턴

역시 코드로 한 번 살펴 봐야겠어요.

확실하게 이해해 봅시다.

Page 19: Design patterns 스터디 -Decorator 패턴

앞에서 다이어그램으로 보여드렸던 것을

다시 한번 그려봤습니다.

보기 좋게 하이라이트 해뒀으니! 찬찬히 한번 읽어보시죠

Page 20: Design patterns 스터디 -Decorator 패턴

왜 이렇게 설계하는거야?? 이해가 안되잖아??

여기에 대한 질문은 main메소드를 보시면 이해가 되실겁니다!

Page 21: Design patterns 스터디 -Decorator 패턴

메인 메소드를 살펴보죠.

아하! 이렇게 첨가물을 new할 때 beverage를 파라미터로 넣어주면 첨가물이 첨가되는군요!!

이게 가능한 이유는 핵심 component인 커피와 첨가물들이 똑같은

“Beverage”라는 클래스를 상속받기 때문입니다!!

이렇게하면 첨가물이 추가된 음료도 결국 Beverage니까 그 음료에다가 또 다른 첨가물을 추가하려고 해도 파라미터로 이전 음료를 넣는것이 가능한거죠!

테스트를 해보니 잘 찍혀 나오는군요! 이젠 더블 모카를 주문해도 문제가 없어요.

Page 22: Design patterns 스터디 -Decorator 패턴

데코레이터 페턴을 이용하면 우리가 아까 배웠던 디자인원칙,

OCP를 지키면서 디자인 할 수 있죠.

즉, 첨가물이나 새로운 종류의 음료를 추가하기 위해서는 기존의 코드를 건드릴 필요 없이 새로운 클래스를 추가해서 확장을

하면 되는거에요.

쉽게 확장할 수 있으면서도 기존의 코드를 변경하지 않으니 OCP를 지켰다고 할 수 있죠.

Page 23: Design patterns 스터디 -Decorator 패턴

몇 몇 질문들이 있을 수 있을 것 같아요.

예를 들면,

“상속이 아니라 구성을 사용하라면서요?? 이것도 결국 상속 아닌가요??”

같은 질문이 있을 수 있을 것 같아요.

Page 24: Design patterns 스터디 -Decorator 패턴

생각 해봅시다.

분명 상속을 이용해 디자인을 하였지만, 그 상속이 무엇을 위한 상속이었을까요?

그건 바로 앞에서 메인 메소드에서 보셨다시피 “형식”을 맞추기 위한 수단인겁니다.

그래서 우리는 손쉽게 첨가물을 추가 할 수 있었죠. 바로 같은 “Beverage”를 상속하고 있다는 점 때문에!!!

그리고 결국 행동을 슈퍼클래스에서 상속 받아 얻게 되는 것이 아니라 첨가물을 추가할 때 마다 얻게되므로 구성을 이용한다고 할 수 있죠.

Page 25: Design patterns 스터디 -Decorator 패턴

실제로 이런 데코레이터 페턴을 이용하는 것을 이미 많이 봐 오셨을 것도 같은데요,

예를 들면, java.io를 이용해 파일 입출력을 할 때,

FileInputStream fis = new FileInputStream(); BufferedInputStream bis = new BufferedInputStream(fis);

이런식으로 이용 할 수 있는 것은 데코레이터 패턴으로 디자인 되어 있기 때문입니다!!!

Page 26: Design patterns 스터디 -Decorator 패턴

수고 많으셨습니다! 어때요, 데코레이터 페턴, 유용해 보이시나요?

다음 시간에는 싱글턴 페턴을 공부해보도록 합시다!