80
Head First 디디디 디디 1/2 데데데데 데데 데데데

[0820 석재호]headfirst디자인패턴

Embed Size (px)

Citation preview

Page 1: [0820 석재호]headfirst디자인패턴

Head First 디자인 패턴 1/2

데브루키 꿜라 석재호

Page 2: [0820 석재호]headfirst디자인패턴

목 차

디자인 패턴 소개

전략 (Strategy) 패턴

옵저버 패턴

데코레이터 패턴

팩토리 패턴

싱글턴 패턴

커맨드 패턴

어댑터 패턴 & 퍼사드 패턴

Page 3: [0820 석재호]headfirst디자인패턴

디자인 패턴

좋은 구조의 소프트웨어 만들자

설 계

구 현 개 선 점 발 견

하 나 의 검 증 된 패 턴 으 로 정 립

Page 4: [0820 석재호]headfirst디자인패턴

디자인 패턴

디자인 패턴은 검증된 KNOW HOW

디자인 패턴은 라이브러리 / 프레임워크의 상위 개념

Page 5: [0820 석재호]headfirst디자인패턴

디자인 패턴의 장점

디자인 패턴은 검증된 해결책 - 더 적은 노력으로 비슷한 문제의 해결이 가능

팀 내 의사소통의 효율성 - 디자인에 대한 아이디어를 간단한 용어만으로 확실히 전달하고 이해할 수 있다

Page 6: [0820 석재호]headfirst디자인패턴

디자인 패턴 , 주의할 점

디자인 패턴은 그 자체로 해답이 되지 않는다 - 각 상황에 맞는 변형이 필요 이를 위해서는 경험을 통한 노하우 습득이 중요

개발 경험이 부족하면 이해하기 어렵다 - … 그래서 이해를 못하고 있습니다…

* 참고로 발표 중 ‘ 인터페이스’ == ‘ 추상클래스’ 라고 보시면 ..

Page 7: [0820 석재호]headfirst디자인패턴

전략 패턴

Page 8: [0820 석재호]headfirst디자인패턴

디자인 원칙

• 애플리케이션에서 달라지는 부분과 달라지지 않는 부분을 분리– 요구사항에 따라 변경될 부분은 따로 캡슐화 시킨다면

이후 바뀌지 않는 부분에 변경을 주지 않고 수정이 가능

• 구현이 아닌 인터페이스에 맞추는 프로그래밍– 요소 간 관계가 느슨해져 프로그램에 유연성이 생기고

동적으로 동작을 변경하는 것이 가능해진다

Page 9: [0820 석재호]headfirst디자인패턴

디자인 원칙

• 상속보다는 구성을 활용한다– 유연성의 향상– 동적인 행동 변경

Page 10: [0820 석재호]headfirst디자인패턴

전략 패턴이란 ?

사용되는 알고리즘군을 정의하고각각을 캡슐화 하여교환해가며 사용할 수 있도록 만든다

Page 11: [0820 석재호]headfirst디자인패턴

전략 패턴 예제파생된 두 오리 클래스가 자신에게 적절한출력을 하도록 Display 함수를 오버라이드

Duck

Quack()Display()

M_Duck

Display() 적절히 오버라이드

R_Duck

Display() 적절히 오버라이드

Page 12: [0820 석재호]headfirst디자인패턴

음… . 잘 나는걸 ?

Duck

Quack()Display()Fly()

M_Duck

Display() 적절히 오버라이드

R_Duck

Display() 적절히 오버라이드

“ 날게 해주세요 .”

Page 13: [0820 석재호]headfirst디자인패턴

음… . 귀여운걸 ?

Duck

Quack()Display()Fly()

M_Duck

Display() 적절히 오버라이드

R_Duck

Display() 적절히 오버라이드

“ 귀여운 고무오리 인형을 추가해주시죠 .”

Gomu_Duck

Quack() 삑삑 소리Display()

Page 14: [0820 석재호]headfirst디자인패턴

음… . 안되겠는걸 ?

Duck

Quack()Display()Fly()

M_Duck

Display() 적절히 오버라이드

R_Duck

Display() 적절히 오버라이드

“ 인형이 왜 날죠 ? 장난하시나 .. ”

Gomu_Duck

Quack() 삑삑 소리Display()

Page 15: [0820 석재호]headfirst디자인패턴

음… .

날지 못하도록Fly() 를 오버라이드 하면

되 겠 는 걸 ?

Gomu_Duck

Quack() 삑삑 소리Display() Fly() { 아무것도 하지 않는다}

Page 16: [0820 석재호]headfirst디자인패턴

음… .

이젠 슬슬 힘든걸 ?

Duck

Quack()Display()Fly()

M_Duck

Display() 적절히 오버라이드

R_Duck

Display() 적절히 오버라이드

“ 날지도 못하고 소리도 안 나는 나무 인형도 ..”

Gomu_Duck

Quack() Display() Fly()

Page 17: [0820 석재호]headfirst디자인패턴

인터페이스를 쓰면 괜찮겠는걸 ?

변화할 수 있는 부분은 따로 빼라고 했었지 ..

부모인 Duck 클래스로부터 Fly() 와 Quack() 을 빼내서 각각을 순수가상함수로 가지는 추상 클래스 Flyable 과 Quackable 을 만들면 어떨까 ? ( C++ 버전… )

필요한 오리 놈들은 이것을 다중상속 받아 저마다 필요한대로 구현하게 되겠지

Page 18: [0820 석재호]headfirst디자인패턴

점점 오리는 추가되고 ..

지나고 보니 나는 법도 우는 법도 거의 동일한데 그 메소드 몇 개 오버라이드 하는게 귀찮아서 87 종의 오리에게 일일이 Fly() 를 넣어주고 102 종의 오리에게 Quack() 을 넣어주게 되었구나

이건 좀 아닌 것 같은걸 ?

Page 19: [0820 석재호]headfirst디자인패턴

전략 패턴의 등장

• 알고리즘군의 정의 , 그리고 캡슐화 필요

• Fly() 와 Quack() 은 다양하게 변화할 수 있다Duck 의 다른 부분은 변화하지 않는다– 변화하는 부분을 떼어놓자

Page 20: [0820 석재호]headfirst디자인패턴

알고리즘군

행 동

나는 행동 우는 행동

똑바로

삐뚤빼뚤

못 남 ㅋ

뒤 로

꽥 꽥

어머니 ~

쾍 쾍

콜록 콜록

Page 21: [0820 석재호]headfirst디자인패턴

알고리즘군의 구현 - 인터페이스와 구현객체

FlyInterface

Fly()

FlyStraightFly()

FlyBackFly()

CannotFlyFly()

QuackInterface

Quack()

QquaackQuack()

GuakQuack()

SilentQuack()

Page 22: [0820 석재호]headfirst디자인패턴

알고리즘군의 사용

Duck

performQuack();performFly();Display();…

FlyInterface *flyInt;QuackInterface *quackInt;

이제 여기에 알고리즘 객체를갈아 끼우기만 하면되겠는걸 ?

새로운 행동이요구된다 해도이 녀석은 더 이상 고칠 필요 없겠는걸 ?

Page 23: [0820 석재호]headfirst디자인패턴

구현보단 인터페이스 . 상속보단 구성

Duck

Fly 인터페이스

GomuDuck

OhDuck

BindaeDuck

똑바로 날기

옆으로 날기

못 날기

Quack 인터페이스

꽥 꽥

엉 엉

뜨얿

Page 24: [0820 석재호]headfirst디자인패턴

의견 교환의 시간

음 .. 설명이 부족한걸 ?

Page 25: [0820 석재호]headfirst디자인패턴

옵저버 패턴

Page 26: [0820 석재호]headfirst디자인패턴

디자인 원칙

• 서로 상호작용을 하는 객체 사이에서는가능하면 느슨하게 결합하는 디자인을 사용한다

이상하게도… 그 얘기가 그 얘기 같은…

Page 27: [0820 석재호]headfirst디자인패턴

옵저버 패턴

한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들에게 연락이 가고자동으로 연락 받은 객체의 내용이 갱신되는 방식

객체 – 주제 (subject) 객체의존하는 다른 객체 – 옵저버 (obse….) 객체

Page 28: [0820 석재호]headfirst디자인패턴

예를 들자면 ..

신문 , 잡지의 구독 매커니즘- 신문사에서 신문을 찍는다- 독자가 신문사에 구독 신청을 하면 , 구독을 해지하기까지 계속해서 배달을 받을 수 있다- 더 보기 싫으면 구독 해지 신청을 한다 . 신문은 더 이상 오지 않는다- 신문사에는 개인 , 영업소 , 기타 회사 등에서 계속해서 구독 및 해지 신청이 온다신문사 = 주제 객체

Page 29: [0820 석재호]headfirst디자인패턴

옵저버 패턴신문사 ( 주제 객체 )

구독자를 등록 , 해지하는 기능 필요등록된 구독자 모두에게 새 신문이 나올 때마다 전달등록된 구독자들을 관리할 목록이 필요

- 옵저버 객체 리스트를 저장할 수 있어야 한다

Page 30: [0820 석재호]headfirst디자인패턴

옵저버 패턴구독자 ( 옵저버 객체 )새 신문이 도착하면 신문을 받아야 함

- 주제 객체의 상태 변화 시 옵저버의 업데이트 함수를 호출 할 수 있어야 함

Page 31: [0820 석재호]headfirst디자인패턴

옵저버 패턴신문사는 구독자가 누구건 동일하게 등록 , 해제구독자도 신문사가 어디건 새 신문을 받는 것은 동일

구현된 객체가 아닌 인터페이스에 맞춰라 !

느슨한 결합으로 유연성을 높여라 !

Page 32: [0820 석재호]headfirst디자인패턴

옵저버 패턴 구조신문사 인터페이스구독자등록 ()구독자해지 ()새신문전달 ()

구독자 인터페이스새신문받기 ()

신문사 구현클래스구독자등록 ()구독자해지 ()새신문전달 ()

추가 _ 상태설정함수()

구독자 구현클래스새신문받기 ()

추가 _ 옵저버용함수()

구독자 여러 개 등록 가능

신문사를 알아야 등록요청 가능

느슨 느슨

Page 33: [0820 석재호]headfirst디자인패턴

느슨느슨 열매의 힘주제는 옵저버가 뭘 하는 애인지 알 필요가 없음옵저버는 언제든지 추가 , 제거가 가능새로운 형식의 옵저버가 나타나도 주제 변경 없음주제와 옵저버는 독립적으로 다른 곳에 재사용이

가능각각의 변경이 서로에게 영향을 주지 않음

Page 34: [0820 석재호]headfirst디자인패턴

다시 찾아온 의견 교환의 시간

보충을 부탁드립니다

옵저버 패턴의 두 가지 방식 주제가 데이터를 보내는 푸시 방식 (방금 본 방식 )

옵저버가 주제로부터 필요한 상태를 빼내는 풀 방식

Page 35: [0820 석재호]headfirst디자인패턴

데코레이터 패턴

Page 36: [0820 석재호]headfirst디자인패턴

디자인 원칙클래스는 확장에 대해서는 열려있어야 하고

코드 변경에 있어서는 닫혀있어야 한다

Page 37: [0820 석재호]headfirst디자인패턴

데코레이터 패턴

객체에 추가적인 요건을 동적으로 첨가한다

서브클래스를 만드는 것을 통해서 기능을 유연하게 확장하는 방법을 제시하는 패턴

Page 38: [0820 석재호]headfirst디자인패턴

데코레이터 패턴책에서는 오만가지 커피를 예로 들어 설명을 하지만 ..

게임 아이템으로 예를 들어 흥미를 유발하겠습니다

사실 흥미유발 안되겠죠 ..

Page 39: [0820 석재호]headfirst디자인패턴

칼칼

“… 좀 너무 밋밋하네요 .

무기 강화 시스템도넣어주시구요 .

불속성 , 바람속성버프도 있으면 좋겠고 ..

음 ..

축복받은 무기랑 저주받은 무기는 기본으로 있어야겠죠 ?”

무기 인터페이스

getDamage();getDescription();

int 데미지 ;

칼getDamage();

도 끼getDamage();

활getDamage();

Page 40: [0820 석재호]headfirst디자인패턴

음…

무기 인터페이스

getDamage();getDescription();

int 데미지 ;

칼getDamage();

도 끼getDamage();

활getDamage();

저주받은 칼

getDamage();

바람의 축복받은 칼

getDamage();강화된 저주받은 칼

getDamage();불의 도끼

getDamage();강화된 얼음의 축복받은 도끼

getDamage();요정의 저주받은 활

getDamage();

강화된 바람의 활

getDamage();

오크족의 드러운 칼

getDamage();

디아 3 룬 + 스킬 조합은 968억개가 넘는다던데… .

Page 41: [0820 석재호]headfirst디자인패턴

바람의

getDamage();

무기와 버프를 모두 따로 따로

칼getDamage();

축복받은

getDamage();칼

getDamage();

데미지 계산

Page 42: [0820 석재호]headfirst디자인패턴

데코레이터 패턴 구조무기와 버프 객체가 동일한 인터페이스로 겹쳐지려면 같은 상속계통에 있어야 한다 - 공통의 부모가 있어야 공통의 그릇이 생긴다

버프는 다중으로 겹쳐지기 위해 자신이 담을 객체를저장할 수 있어야 한다 ( 무기는 그럴 필요 없다 )

- 다시 말해 기반 클래스의 포인터를 멤버로 가진다

Page 43: [0820 석재호]headfirst디자인패턴

데코레이터 패턴 구조무기 인터페이스

getDamage();getDescription();

버프 인터페이스

getDescription();

칼getDamage();getDescription(); 바 람 의

getDamage();getDescription();

무기인터페이스 * 안쪽버프 ;

강 화 된

getDamage();getDescription();

무기인터페이스 * 안쪽버프 ;

도 끼getDamage();getDescription();

Page 44: [0820 석재호]headfirst디자인패턴

객체 겹치기

생성자나 기타 함수의 인수로 객체를 받아서 ..Sword kal;

Powered kangWha(kal);

WindElement baram(kangWha);

baram.getDamage();

호출 시 강화된 바람의 칼 데미지가 계산되어 나옴Description 도 같은 방식으로 구현 가능

Page 45: [0820 석재호]headfirst디자인패턴

의 to the 견 to the 교 to the 환

실제로 위와 같은 경우 이러한 패턴이 유효한지 ..?

데코레이터 패턴의 실제 사례 : 자바 I/OFileInputStream

BufferedInputStream

LineNumberInputStream 들이 안쪽 객체를 싸고 동작

Page 46: [0820 석재호]headfirst디자인패턴

팩토리 패턴

Page 47: [0820 석재호]headfirst디자인패턴

스타 2 하시는 분[email protected]친추

실버 , 브론즈 우대

Page 48: [0820 석재호]headfirst디자인패턴

팩토리 패턴사실 팩토리 자체는 디자인 패턴이 아님디자인 패턴인 ‘팩토리 메서드 패턴’을 설명하기 위해 필요

팩토리 메서드 패턴 객체를 생성하기 위한 인터페이스를 정의하는데 어떤 클래스의 인터페이스를 만들지는 서브클래스에서 결정한다

Page 49: [0820 석재호]headfirst디자인패턴

화염차 (Hellion)

단축키 - E

크루시오 공성전차 (Siege Tank)

단축키 - S

토르 (Thor)

단축키 - T

Page 50: [0820 석재호]headfirst디자인패턴

생산을 .. Unit *factoryUnit;

If(입력키 == ‘E’)

factoryUnit = new Hellion();

Else if(입력키 == ‘S’)

factoryUnit = new Siege();

Else if(입력키 == ‘T’)

factoryUnit = new Thor();

Page 51: [0820 석재호]headfirst디자인패턴

팩토리의 필요성

이전과 같은 방식의 코드는변경이나 확장 시마다 코드의 추가 제거가 필요관리 갱신이 어려워지고 오류 발생 가능성이 높아짐

Page 52: [0820 석재호]headfirst디자인패턴

다시 한 번 디자인 원칙

바뀌는 부분을 안 바뀌는 부분에서 떼어내 캡슐화

바뀌는 부분은 방금 본 객체 생성 부분안 바뀌는 부분은 그 객체를 가지고 행해지는 일련의 동작들 (attack, move 등 동일한 인터페이스로 동작 )

Page 53: [0820 석재호]headfirst디자인패턴

생성부 캡슐화

아까의 코드를 Factory 라는 클래스에 넣고 메인부에서는 Factory 객체를 만들어키 값으로 유닛을 생성하는 함수를 호출한다

Factory* fact; // 객체 초기화 코드 생략Unit* newUnit;

newUnit = fact->createUnit(key); // 캡슐화된 결과

Page 54: [0820 석재호]headfirst디자인패턴

군수공장의 다양화에도 ..

새로운 형태의 공장 추가에도군수공장 자체는 변화 필요없다

유닛 생산시에 어떤 유닛이 생산될지를 서브클래스가 결정하게 된다

군수공장 인터페이스

createUnit();displayUnit();

비싼 군수공장

createUnit();

싼 군수공장

createUnit();

Page 55: [0820 석재호]headfirst디자인패턴

유닛 생산을 위해Unit

싸구려 토르

싸구려 화염차

싸구려 탱크

비싼 토르

비싼 화염차

비싼 탱크

비싼 군수공장

createUnit();

당연히 군수공장이 유닛을 알아야 유닛을 만들 수 있다

Page 56: [0820 석재호]headfirst디자인패턴

팩토리 메서드 패턴 구조

제품 인터페이스

구상 제품

팩토리 인터페이스

factoryMethod();otherMethod();

구상 팩토리

factoryMethod();

Page 57: [0820 석재호]headfirst디자인패턴

의견 교환의 시간

꼭 팩토리 메서드를 추상으로 만들 필요는 없다

추상 팩토리 패턴 ..

Page 58: [0820 석재호]headfirst디자인패턴

싱글턴 패턴

Page 59: [0820 석재호]headfirst디자인패턴

싱글턴 패턴

해당 클래스의 인스턴스가 하나만 만들어지고어디서든지 그 인스턴스에 접근할 수 있도록 하기 위한 패턴

유일무이한 객체를 필요한 타이밍에 생성

Page 60: [0820 석재호]headfirst디자인패턴

싱글턴 패턴의 이점

전역변수에 비해필요할 때만 만들 수 있어 자원 절약

여러 번역단위에서 중복 생성할 위험이 없음

Page 61: [0820 석재호]headfirst디자인패턴

싱글턴 패턴의 이점

전역변수에 비해필요할 때만 만들 수 있어 자원 절약

여러 번역단위에서 중복 생성할 위험이 없음

Page 62: [0820 석재호]headfirst디자인패턴

고전적인 싱글턴 패턴 구현법생성자를 통한 생성을 막아라

- 생성자의 private 선언

해당 클래스의 포인터 멤버 변수를 내부에 하나 생성

정적 멤버 함수를 만들어라- 포인터가 null 이면 새 객체 생성 , 아닐 시 그대로 해당 포인터를 리턴한다

Page 63: [0820 석재호]headfirst디자인패턴

class Singleton {

public :

static Singleton* getInstance() {

if(singleInstance == null)

singleInstance = new Singleton();

return singleInstance;

}

private :

static Singleton* singleInstance;

Singleton() { }

}

Page 64: [0820 석재호]headfirst디자인패턴

의견 교환의 시간

과연 멀티스레드 환경에서도 유일무이할까 ?

싱글턴은 언제 파괴되는가 ?

피닉스 싱글턴 ? ( http://ikpil.com/1275 )

Page 65: [0820 석재호]headfirst디자인패턴

어댑터 패턴 & 퍼사드 패턴

Page 66: [0820 석재호]headfirst디자인패턴

어댑터 패턴과 퍼사드 패턴‘ 적응시키기’

Page 67: [0820 석재호]headfirst디자인패턴

어댑터 패턴

한 클래스의 인터페이스를 클라이언트에서사용하고자 하는 다른 인터페이스로 변환

인터페이스 호환성 문제 때문에 같이 쓸 수 없는클래스들을 연결해서 쓸 수 있다

Page 68: [0820 석재호]headfirst디자인패턴

어댑터 패턴

오리 .. 우리 다시 만나게 되었는걸 ?

M_Duck 이나 R_Duck 객체를 만들고 그 포인터를인자로 testDuck 을 호출할 수 있겠는걸 ?

Duck

Quack();Fly();

M_Duck

Quack();Fly();

R_Duck

Quack();Fly();

메 인

Void testDuck(Duck* d) { d->Quack(); d->Fly();}

Page 69: [0820 석재호]headfirst디자인패턴

“ 그간 편했죠 ? 칠면조도 넣어주시죠 ?”

칠면조 ? 이건 뭘 어쩌라는 건지 ..

testDuck 의 인자로는 넣을 수가 없어 ..

이깟 새 때문에 메인 파트를 고치고 새로운 함수를 만들어 따로 호출해야겠는걸 ?

어차피 우는 것은 같은데 망할 인터페이스 때문에 ..

이젠 내가 울고 싶은걸 ?

Turkey

Gobble();Fly();

WildTurkey

Gobble();Fly();

메 인

Void testDuck(Duck* d) { d->Quack(); d->Fly();}

Page 70: [0820 석재호]headfirst디자인패턴

어댑터 !!!

TurkeyAdapter

Quack();Fly();

TurkeyAdapter

TurkeyAdapter(Turkey* turkey): tu(turkey) {}

Void Quack() { tu.Gobble(); }

Void Fly(){ tu.Fly(); }

Duck

Quack();Fly();

Turkey *tu;

Page 71: [0820 석재호]headfirst디자인패턴

어댑터 패턴

클라이언트에서는 어댑터가 껴있는지 알지도 못하겠는걸 ?

어떠냐 !!!!! 요구사항의 괴롭힘에도 나는 굴하지 않는걸 !!!!

Duck

Quack();Fly();

M_Duck

Quack();Fly();

M_Duck* mD = new M_Duck();WildTurkey* wT = new WildTurkey();Duck* tA = new TurkeyAdapter(wT);

testDuck(mD);testDuck(tA); // 문제없이 동작

TurkeyAdapter

Page 72: [0820 석재호]headfirst디자인패턴

어댑터 패턴 구조

Target Interface

Request()

Client

Adapter

Request()

Adaptee

specificRequest()

어탭터에서 타겟 인터페이스를 구현 . 어댑티를 구성을 통해 보유 .클라이언트가 구현이 아닌 인터페이스에 연결된다 어댑터를 교체해가며 유연한 사용이 가능하다는 이야기

Page 73: [0820 석재호]headfirst디자인패턴

클래스 어댑터지금까지 배운 것은 객체 어댑터 ( 구성 활용 )

클래스 어댑터는 다중 상속이 가능한 언어에서 사용 가능

특정 어댑티 클래스에만 적용되는 어댑터 클래스라는 단점어댑티의 행동을 오버라이드 할 수 있는 장점어댑터 내에 어댑티 객체가 필요하지 않아 효율적

Target Interface

Request()

Client

Adapter

Request()

Adaptee

specificRequest()

Page 74: [0820 석재호]headfirst디자인패턴

퍼사드 패턴현재 이 페이지 작성시각 8월 20 일 오후 1:50……

아직 씻지도 못했는데…… 아아아아앙ㅁ ;ㅣ나얼

어떤 서브시스템의 일련의 인터페이스에 대한 통합된 인터페이스 제공

서브시스템을 더 쉽게 사용할 수 있다

Page 75: [0820 석재호]headfirst디자인패턴

디자인 원칙

최소 지식 원칙 – 정말 친한 친구하고만 얘기하라

객체간 상호 관계에서 서로 서로는서로에 대해 아는 것이 적을 수록 좋다

Page 76: [0820 석재호]headfirst디자인패턴

영화를 봅시다

팝콘 기계 ON();

팝콘 튀기기 ON();

전등 OFF();

프로젝터 ON();

앰프 ON();

DVD 플레이어 ON();

Page 77: [0820 석재호]headfirst디자인패턴

에이 복잡해… 그냥…

MovieFacade팝콘기계

DVD 플레이어

앰프

스 크 린DVD 플레이어

조 명 프 로 젝 터

Page 78: [0820 석재호]headfirst디자인패턴

하나로 통합

MovieFacade

Void WatchMovie(){팝콘 . 기계 ON();팝콘 . 튀기기 ON();전등 . OFF();프로젝터 . ON();앰프 . ON();DVD 플레이어 . ON();

}

클라이언트는 MovieFacade 객체를 만들고WatchMovie() 를 호출하는 것 하나로

적절한 조명에서 빵빵한 음향으로맛있는 팝콘을 먹으며 영화를 보는 것을

서브시스템에 대한 신경을 쓸 필요없이즐길 수 있습니다

Page 79: [0820 석재호]headfirst디자인패턴

마지막 의견 교환의 시간

Page 80: [0820 석재호]headfirst디자인패턴

감 사 합 니 다