객체지향설계와패턴 lecture #11: 구조패턴(2) · pattern #8 –컴포지트패턴...

54
객체지향 설계와 패턴 객체지향 설계와 패턴 Lecture #11: 구조 패턴(2) Eun Man Choi [email protected]

Upload: others

Post on 31-Jan-2020

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

객체지향 설계와 패턴

Lecture #11: 구조 패턴(2)

객체지향 설계와 패턴

Lecture #11: 구조 패턴(2)

Eun Man [email protected]

Page 2: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

학습 목표

l 컴포지트 패턴

l 어뎁터 패턴

l 프록시 패턴

l 실습 문제

2

l 컴포지트 패턴

l 어뎁터 패턴

l 프록시 패턴

l 실습 문제

Page 3: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

Pattern #8 – 컴포지트 패턴

l 패턴 요약l 기본 클래스와 이를 포함하는 컨테이너 클래스를 재귀적인 형태로 표현l 객체들의 집합을 다룰 때 유용l e.g. 폴더 안의 파일

객체의 트리를 나타내는 데 사용

3

객체의 트리를 나타내는 데 사용

Page 4: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

컴포지트 패턴의 기본 모델

Component

leaf nodenon-leaf node객체

클래스 1..n

4NonLeafNode

Component

“모든 객체는component 객체”

“non-leaf 노드는하나 이상의components”

클래스 1..n

Page 5: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

컴포지트 패턴 : 동 기

회사에서당신이맡은업무는 Drawing Tool 을 개발하는것이다.이 Drawing Tool은 직선, 사각형, 원 등의 그림을 그릴 수 있으며, 각개체를 이동 및 속성 수정이 가능하다. 또한 몇 개의 개체를 묶어하나의 Group 개체로만들수도있다.이러한 요구사항을 만족하기 위해서 어떻게 그림 개체 클래스들을설계해야되는가?

회사에서당신이맡은업무는 Drawing Tool 을 개발하는것이다.이 Drawing Tool은 직선, 사각형, 원 등의 그림을 그릴 수 있으며, 각개체를 이동 및 속성 수정이 가능하다. 또한 몇 개의 개체를 묶어하나의 Group 개체로만들수도있다.이러한 요구사항을 만족하기 위해서 어떻게 그림 개체 클래스들을설계해야되는가?

5

Page 6: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

컴포지트 패턴 : 동 기

Circle

Rectangle

GroupGroup

Rectangle

Group

LineLineLineLine

Circle

Circle

Line

전체 그림개체들을하나의 group으로 간주

6

Line

Rectangle Line Circle Group

[필요한 클래스들]

Circle Line

Group

LineLineLineLine

Part-Whole 구조

Page 7: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

컴포지트 패턴 : 동 기

[추상 클래스 만듦]

Group과 Figure와의관계는?

Rectangle Line Circle Group

Figure

[추상 클래스 만듦]

Group과 Figure와의관계는?

7

Group Figure*

Circle Line

Group

LineLineLineLine

Page 8: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

컴포지트 패턴 : 동 기

[연산을 추가한 클래스 구조]

8

Group에 개체 추가및 삭제 연산

leaf or terminal nodes

Page 9: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

컴포지트 패턴 : 동 기

l 원시 코드class Figure {public:

virtual void draw() =0;virtual void move() =0;virtual void add(Figure *) {}virtual void remove(Figure *) {}Figure *getChild(int) {}

};

class Rectangle : public Figure {public:

virtual void draw() { … }virtual void move() { … }

};class Line : public Figure {public:

virtual void draw() { … }virtual void move() { … }

};class Circle : public Figure {public:

virtual void draw() { … }virtual void move() { … }

};

class Group : public Figure {public:

virtual void draw() {Figure *f;for( int i=0; (f=getChild(i)) !=NULL ; ++i )

f->draw();} virtual void move() {

…}

// Children Handling Routinevirtual void add(Figure *) { … }virtual void remove(Figure *) { … }Figure *getChild(int) { … }…

};

가지고 있는 모든Figure 객체에

draw 함수 호출

9

class Figure {public:

virtual void draw() =0;virtual void move() =0;virtual void add(Figure *) {}virtual void remove(Figure *) {}Figure *getChild(int) {}

};

class Rectangle : public Figure {public:

virtual void draw() { … }virtual void move() { … }

};class Line : public Figure {public:

virtual void draw() { … }virtual void move() { … }

};class Circle : public Figure {public:

virtual void draw() { … }virtual void move() { … }

};

class Group : public Figure {public:

virtual void draw() {Figure *f;for( int i=0; (f=getChild(i)) !=NULL ; ++i )

f->draw();} virtual void move() {

…}

// Children Handling Routinevirtual void add(Figure *) { … }virtual void remove(Figure *) { … }Figure *getChild(int) { … }…

};

내부 Figure 객체 관리(추가, 삭제, 검색)는 이를 위한자료구조가 필요

Page 10: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

컴포지트 패턴

l 의도l Part-whole Hierarchy를 표현하기 위하여 객체들을 트리 구조로 구성l Client 가 개개의 객체와 그룹 객체를 동일하게 취급할 수 있게 만든다.

l 적용 범위l 객체들을 part-whole hierarchy 구조로 표현하고자 할 때l 개개의 객체와 그룹 객체를 동일하게 취급하고자 할 때

10

Page 11: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

컴포지트 패턴

구조

11

aComposite

aLeaf

aLeaf

aLeafaLeaf

aLeaf

aCompositeaLeaf[실행시 객체들의 일반적인 구성]

Page 12: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

컴포지트 패턴

l 참여 요소l 컴포넌트(Figure)

• 리프들의 공통 인터페이스 정의예) draw(), move()

• Child 객체들을 접근하고 관리하기 위한 인터페이스 정의예) add(Component), remove(Component), getChild(int)

l 리프(Rectangle, Line, Circle)• Child 객체를 가지지 않는 객체• 조합에 이용되는 객체들의 기본적 연산들을 정의

l 컴포지트(Group)• Child 객체들을 가지는 객체• 위임 방식으로 리프들의 공통 인터페이스를 구현

l 클라이언트• 모든 객체들을 컴포넌트 객체로 간주하여 이용

l 참여 요소l 컴포넌트(Figure)

• 리프들의 공통 인터페이스 정의예) draw(), move()

• Child 객체들을 접근하고 관리하기 위한 인터페이스 정의예) add(Component), remove(Component), getChild(int)

l 리프(Rectangle, Line, Circle)• Child 객체를 가지지 않는 객체• 조합에 이용되는 객체들의 기본적 연산들을 정의

l 컴포지트(Group)• Child 객체들을 가지는 객체• 위임 방식으로 리프들의 공통 인터페이스를 구현

l 클라이언트• 모든 객체들을 컴포넌트 객체로 간주하여 이용

12

Page 13: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

컴포지트 패턴

l 협동l 클라이언트는 컴포지트 구조에 있는 각 객체들을 이용할 때 컴포넌트 인

터페이스를 사용한다.l 클라이언트가 특정 객체에 어떤 요청을 보내면(함수를 호출하면), 해당

객체가 리프 객체일 경우엔 직접적으로 그 요청이 처리되고, 해당 객체가컴포지트 객체일 경우엔 그 요청은 컴포지트 객체가 가지고 있는 모든 컴포넌트 객체들에게 재 전송된다.

13

Client

aLeafdraw

draw 요청 직접처리component interface

aCompsite

component interfacedraw

aComponent

aComponent

draw

drawdraw 요청 재 전송

Page 14: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

컴포지트 패턴

l 결과l Primitive 객체와 composite 객체로 구성된 클래스 hierarchy를 정의l Client code가 단순해진다.l 새로운 종류의 컴포넌트 객체를 추가하기 쉽다.

• 기존의 코드를 수정하지 않아도 새 컴포넌트 추가가 가능

14

Page 15: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

컴포지트 패턴

l 구현l Explicit parent references

• child 객체에서 parent 객체(composite)로의 이동을 위하여 parent reference를 모든 객체마다 가지게 할 수 있다.

• 이 경우, parent reference 변수와 그 관리는 Component 클래스에서 구현하는 것이 일반적이다.-> Leaf, Composite 클래스에서는 parent의 구현에 대해 신경쓰지않아도 됨

l Sharing Components• child 객체들이 독점적으로 한 composite 객체에만 소속되는 것이

아니라 여러 composite 객체들에 동시에 공유될 수 있다.• parent reference 를 유지하려면, 단일 reference가 아닌 복수

references 를 유지 관리하여야 한다.

l 구현l Explicit parent references

• child 객체에서 parent 객체(composite)로의 이동을 위하여 parent reference를 모든 객체마다 가지게 할 수 있다.

• 이 경우, parent reference 변수와 그 관리는 Component 클래스에서 구현하는 것이 일반적이다.-> Leaf, Composite 클래스에서는 parent의 구현에 대해 신경쓰지않아도 됨

l Sharing Components• child 객체들이 독점적으로 한 composite 객체에만 소속되는 것이

아니라 여러 composite 객체들에 동시에 공유될 수 있다.• parent reference 를 유지하려면, 단일 reference가 아닌 복수

references 를 유지 관리하여야 한다.

15

Page 16: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

컴포지트 패턴

l Declaring the child management operations in the Component class

l child 객체들을 관리하는 함수들을 1) Component class에 선언하는 것과 2) Composite class에만 선언하는 것, 둘 간의 장단점은?

1) component에 선언 2) composite에만 선언

16

Page 17: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

컴포지트 패턴

l How to manages the child objects?l What is the data structure? tree? linked-list? array? or hash?l Is child ordering important?

-> C++의 경우 STL* 의 List 를 주로 사용. (검색은 Iterator를 이용)

l Who should delete components?l It’s usually best to make a composite responsible for deleting its

children.

l How to manages the child objects?l What is the data structure? tree? linked-list? array? or hash?l Is child ordering important?

-> C++의 경우 STL* 의 List 를 주로 사용. (검색은 Iterator를 이용)

l Who should delete components?l It’s usually best to make a composite responsible for deleting its

children.

17 * Standard Template Library

Page 18: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

컴포지트 패턴: 사례 #1

l 컴퓨터 견적l 컴퓨터와 같은 기계장치(Equipment)들은 내부에 작은 장치들로 구성되

어 있는 Part-whole 구조로 구성된다.l 컴퓨터의 전체 가격을 계산하려면, 모니터와 본체가격을 계산해야 하고,

본체가격은 다시 본체를 이루는 case, power, mother board, hard disk, ram, cpu, … 등의 가격의 총합으로 계산할 수 있다.

18

컴퓨터장비

모니터

CPU MotherBoard

본체

HDD

Equipment

Monitor HDD CPU MotherBoard CompositeEquipment

PCBody

Page 19: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

컴포지트 패턴: 사례 #1

class Equipment {public:

virtual ~Equipment();

const char* Name() { return _name; }

virtual Watt Power();virtual Currency Price();

virtual void Add(Equipment*);virtual void Remove(Equipment*);virtual Iterator<Equipment*>* CreateIterator();

protected:Equipment(const char*);

private:char* _name;int _price;

};

현 장치의 전체 소비전력과가격을 계산하는 함수들

19

class Equipment {public:

virtual ~Equipment();

const char* Name() { return _name; }

virtual Watt Power();virtual Currency Price();

virtual void Add(Equipment*);virtual void Remove(Equipment*);virtual Iterator<Equipment*>* CreateIterator();

protected:Equipment(const char*);

private:char* _name;int _price;

};

child 객체들을 검색하기위한 Iterator 생성 함수

Page 20: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

컴포지트 패턴: 사례 #1

class Monitor : public Equipment {public:

Monitor(const char *name, int price) {_name = strdup(name);_price = price;

}virtual ~Monitor();virtual Watt Power();virtual Currency Price() {

return _price;}

private:int _price;

};

class CPU : public Equipment {…

};class HDD : public Equipment {

…};class MotherBoard : public Equipment {

…};

class CompositeEquipment : public Equipment {public:

virtual ~CompositeEquipment();

virtual Watt Power();virtual Currency Price () {

Iterator<Equipment*>* i = CreateIterator();Currency total = 0;

for (i->First(); !i->IsDone(); i->Next()) {total += i->CurrentItem()->Price();

}delete i;return total;

}

virtual void Add(Equipment*);virtual void Remove(Equipment*);virtual Iterator<Equipment*>* CreateIterator();

protected:CompositeEquipment(const char*);

private:List<Equipment*> _equipment;

};20

class Monitor : public Equipment {public:

Monitor(const char *name, int price) {_name = strdup(name);_price = price;

}virtual ~Monitor();virtual Watt Power();virtual Currency Price() {

return _price;}

private:int _price;

};

class CPU : public Equipment {…

};class HDD : public Equipment {

…};class MotherBoard : public Equipment {

…};

class CompositeEquipment : public Equipment {public:

virtual ~CompositeEquipment();

virtual Watt Power();virtual Currency Price () {

Iterator<Equipment*>* i = CreateIterator();Currency total = 0;

for (i->First(); !i->IsDone(); i->Next()) {total += i->CurrentItem()->Price();

}delete i;return total;

}

virtual void Add(Equipment*);virtual void Remove(Equipment*);virtual Iterator<Equipment*>* CreateIterator();

protected:CompositeEquipment(const char*);

private:List<Equipment*> _equipment;

};

_equipment의Iterator를 이용하여

child 객체 접근

Page 21: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

컴포지트 패턴: 사례 #1

// Client CodeMonitor *monitor = new Monitor(“PC Monitor”, 300);CPU *cpu = new CPU(“PC CPU”, 100);HDD *hdd = new HDD(“PC Hard Disk Drive”, 120);MotherBoard *mb = new MotherBoard(“PC MotherBoard”, 50);

PCSet *pcSet = new CompositeEquipment(“PC Set”);PCBody *pcBody = new CompositeEquipment(“PC Body”);

pcBody->Add(cpu);pcBody->Add(hdd);pcBody->Add(MotherBoard);pcSet->Add(monitor);pcSet->Add(pcBody);

cout << pcSet->Price();

class PCSet : public CompositeEquipment {public:

PCSet(const char *name) {_name = strdup(name);

}virtual ~PCSet();

};

class PCBody : public CompositeEquipment {public:

PCBody(const char *name) {_name = strdup(name);

}virtual ~PCBody();

};

21

// Client CodeMonitor *monitor = new Monitor(“PC Monitor”, 300);CPU *cpu = new CPU(“PC CPU”, 100);HDD *hdd = new HDD(“PC Hard Disk Drive”, 120);MotherBoard *mb = new MotherBoard(“PC MotherBoard”, 50);

PCSet *pcSet = new CompositeEquipment(“PC Set”);PCBody *pcBody = new CompositeEquipment(“PC Body”);

pcBody->Add(cpu);pcBody->Add(hdd);pcBody->Add(MotherBoard);pcSet->Add(monitor);pcSet->Add(pcBody);

cout << pcSet->Price();

Page 22: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

사례 #2: Bank/Teller Example

Client

reports

Supervisoradd(Employee)

EmployeestateName()

1..n

ClerkstateName()

TellerstateName()

22

Supervisoradd(Employee)

Setup

ClerkstateName()

PresidentstateName()

TellerstateName()

ManagerstateName()

Page 23: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

사례 #2: Bank/Teller Example

:Client

stateName()

pete:President

xxxx:Employee

:Setp

doClientTasks()

stateName()

xxxx:Employeexxxx

:Employeexxxx:Employee*

23

stateName()

• Creates the tree of Employee objectswith Pete as President

Page 24: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

Pattern #9 – 어뎁터 패턴

l 패턴 요약l 원하는 인터페이스를 추상 클래스로 정의l 이를 상속하는 어뎁터 클래스를 만들고 이를 요구하는 기능을 가진 클래

스(adaptee)와 메시지를 교환하게 함

어플리케이션의 기능을 외부에서 필요한 형태로

수정하여 사용하도록 함

24

어플리케이션의 기능을 외부에서 필요한 형태로

수정하여 사용하도록 함

Page 25: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

어뎁터 패턴: 동 기

당신은 금융권 전산화 시스템 개발팀의 일원으로, 통신보안 관련 쪽개발을 맡았다. 개발 기간이 빠듯하긴 하지만 다행히 다른프로젝트를 수행할 때 개발해 놓은 통신보안 코드들이 있어서일정을 맞출 수 있을 것 같다. 그런데 한가지 문제점은, 예전프로젝트 때 개발된 통신보안 코드들은 A사의 통신 보안 프로토콜Library를 사용하는데 비하여, 새 프로젝트에서는 B사의 통신 보안프로토콜 Library를 사용하도록 결정되었다. 재사용하려는 통신보안 코드들을 전면적으로 수정하지 않고 A사의 Library를 B사의Library로 대체할수 있는방법은없을까?

당신은 금융권 전산화 시스템 개발팀의 일원으로, 통신보안 관련 쪽개발을 맡았다. 개발 기간이 빠듯하긴 하지만 다행히 다른프로젝트를 수행할 때 개발해 놓은 통신보안 코드들이 있어서일정을 맞출 수 있을 것 같다. 그런데 한가지 문제점은, 예전프로젝트 때 개발된 통신보안 코드들은 A사의 통신 보안 프로토콜Library를 사용하는데 비하여, 새 프로젝트에서는 B사의 통신 보안프로토콜 Library를 사용하도록 결정되었다. 재사용하려는 통신보안 코드들을 전면적으로 수정하지 않고 A사의 Library를 B사의Library로 대체할수 있는방법은없을까?

25

당신은 금융권 전산화 시스템 개발팀의 일원으로, 통신보안 관련 쪽개발을 맡았다. 개발 기간이 빠듯하긴 하지만 다행히 다른프로젝트를 수행할 때 개발해 놓은 통신보안 코드들이 있어서일정을 맞출 수 있을 것 같다. 그런데 한가지 문제점은, 예전프로젝트 때 개발된 통신보안 코드들은 A사의 통신 보안 프로토콜Library를 사용하는데 비하여, 새 프로젝트에서는 B사의 통신 보안프로토콜 Library를 사용하도록 결정되었다. 재사용하려는 통신보안 코드들을 전면적으로 수정하지 않고 A사의 Library를 B사의Library로 대체할수 있는방법은없을까?

당신은 금융권 전산화 시스템 개발팀의 일원으로, 통신보안 관련 쪽개발을 맡았다. 개발 기간이 빠듯하긴 하지만 다행히 다른프로젝트를 수행할 때 개발해 놓은 통신보안 코드들이 있어서일정을 맞출 수 있을 것 같다. 그런데 한가지 문제점은, 예전프로젝트 때 개발된 통신보안 코드들은 A사의 통신 보안 프로토콜Library를 사용하는데 비하여, 새 프로젝트에서는 B사의 통신 보안프로토콜 Library를 사용하도록 결정되었다. 재사용하려는 통신보안 코드들을 전면적으로 수정하지 않고 A사의 Library를 B사의Library로 대체할수 있는방법은없을까?

ClientCode

AProtocolconnect()send()receive()disconnect()

[기존시스템]

ClientCode

BProtocolsetTarget()open()write()read()close()

[개발시스템]

A사 Library Class B사 Library Class

Page 26: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

어뎁터 패턴: 동 기

l 일반적 접근 방법l 기존의 Client Code 내에서 A Library(AProtocol) 부분을 모두 B

Library(BProtocol)로 대체하고, AProtocol 객체의 함수 호출부분을 BProtocol 객체의 함수 호출로 바꾼다.

// 기존 Client Code#include “AProtocol.h”

AProtocol proto;proto.connect(“xyz.com”,50);proto.send(msg);…proto.receive(msg);…proto.disconnect();

// 수정된 Client Code#include “BProtocol.h”

BProtocol proto;proto.setTarget(“xyz.com”,50);proto.open();proto.write(msg);…proto.read(msg);…proto.close();

26

// 기존 Client Code#include “AProtocol.h”

AProtocol proto;proto.connect(“xyz.com”,50);proto.send(msg);…proto.receive(msg);…proto.disconnect();

// 수정된 Client Code#include “BProtocol.h”

BProtocol proto;proto.setTarget(“xyz.com”,50);proto.open();proto.write(msg);…proto.read(msg);…proto.close();

문제점: 기존 Client 코드 전체에 산재해 있는 A Library 관련 코드를 모두 수정하여야 한다.

Page 27: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

어뎁터 패턴: 동 기

l 해결방안l 기존 Client Code 를 그대도 재 사용하기 위해서는 BProtocol 인터페이

스를 AProtocol의 인터페이스로 변환하는 것이 필요하다. l BProtocol 코드를 직접 변경할 수는 없으므로, Client Code와

BProtocol 사이에 중재자 역할을 하는 새로운 클래스를 작성한다(새로운클래스 이름은 A Library의 클래스 명인 AProtocol로 설정)

// 기존 Client Code#include “AProtocol.h”

AProtocol proto;proto.connect(“xyz.com”,50);proto.send(msg);…proto.receive(msg);…proto.disconnect();

BProtocolsetTarget()open()write()read()close()

AProtocolconnect()send()receive()disconnect()

27

// 기존 Client Code#include “AProtocol.h”

AProtocol proto;proto.connect(“xyz.com”,50);proto.send(msg);…proto.receive(msg);…proto.disconnect();

BProtocolsetTarget()open()write()read()close()

AProtocolconnect()send()receive()disconnect()

A Library의 클래스가 아니고,새로 작성된 클래스

Page 28: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

어뎁터 패턴: 동 기

class AProtocol {public:

void connect(char *url, int port) {_bp->setTarget(url, port);_bp->open();

}void send(char *msg) {

_bp->write(msg);}void receive(char *msg) {

_bp->write(msg);}void disconnect() {

_bp->close();}void setBProtocol(BProtocol *bp) {

_bp = bp;}

private:BProtocol *_bp;

};

ClientCode

BProtocol객체

28

class AProtocol {public:

void connect(char *url, int port) {_bp->setTarget(url, port);_bp->open();

}void send(char *msg) {

_bp->write(msg);}void receive(char *msg) {

_bp->write(msg);}void disconnect() {

_bp->close();}void setBProtocol(BProtocol *bp) {

_bp = bp;}

private:BProtocol *_bp;

};

ClientCode

Client Code가AProtocol Interface를 가지고BProtocol 객체를이용할 수 있도록만들어 줌

Page 29: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

어뎁터 패턴: 구 조

Client

AbstractClassclientNameForRequiredMethod()

AdapterclientNameForRequiredMethod()

adaptee

RequiredClassrequiredMethod()

29

AdapterclientNameForRequiredMethod()

{ adaptee. requiredMethod();}

Page 30: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

어뎁터 패턴: Sequence Diagram

:Client

clientNameForRequiredMethod()

:AbstractClass :Adapter

RequiredMethod()

adaptee:RequiredClass

30

Page 31: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

어뎁터 패턴

l 의 도l 특정 클래스의 인터페이스를 클라이언트가 원하는 인터페이스로 변환한다.

l 별 명l Wrapper

l 적용 분야l 기존에 존재하는 클래스를 재사용하고 싶지만, 원하는 인터페이스와 맞지 않을 때l 미리 정해져 있지 않은 클래스들과 상호 작용할 수 있는 재사용 가능 클래스를 만

들려는 경우

l 의 도l 특정 클래스의 인터페이스를 클라이언트가 원하는 인터페이스로 변환한다.

l 별 명l Wrapper

l 적용 분야l 기존에 존재하는 클래스를 재사용하고 싶지만, 원하는 인터페이스와 맞지 않을 때l 미리 정해져 있지 않은 클래스들과 상호 작용할 수 있는 재사용 가능 클래스를 만

들려는 경우

31

Page 32: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

어뎁터 패턴

l 구 조l Class adapter: 상속을 이용

l Object adapter: 위임을 이용

l 구 조l Class adapter: 상속을 이용

l Object adapter: 위임을 이용

32

Page 33: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

어뎁터 패턴

l 구성 요소l Target (AProtocol)

• 클라이언트가 사용하는 도메인 종속적인 인터페이스를 정의한다.

l Client• Target 인터페이스를 통하여 Adaptee 기능을 활용한다.

l Adaptee (BProtocol)• 인터페이스 변화가 필요한 클래스

l Adapter (AProtocol)• Target interface를 통하여 들어오는 클라이언트의 요청을 Adaptee에게 전달해주는 역

할 수행

l 협 동l Client는 Adapter의 함수를 호출하면, Adapter는 Adapter에게 해당 요청을 수행

하는 함수를 호출한다.

l 구성 요소l Target (AProtocol)

• 클라이언트가 사용하는 도메인 종속적인 인터페이스를 정의한다.

l Client• Target 인터페이스를 통하여 Adaptee 기능을 활용한다.

l Adaptee (BProtocol)• 인터페이스 변화가 필요한 클래스

l Adapter (AProtocol)• Target interface를 통하여 들어오는 클라이언트의 요청을 Adaptee에게 전달해주는 역

할 수행

l 협 동l Client는 Adapter의 함수를 호출하면, Adapter는 Adapter에게 해당 요청을 수행

하는 함수를 호출한다.

33

Client Adapter Adapteemsg1 msg1’

Page 34: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

어뎁터 패턴

l 결과l How much adapting does Adapter do?

• Adapter와 Adaptee 간의 inteface 차이 정도에 따라 작업의 수준이달라짐.

l Trade-offs of Class and Object adapters

l 구현l Implementing class adapters in C++

• 일반적으로 Adapter class 가 Target class는 public으로, Adaptee class는 private으로 상속 받는다.

l 결과l How much adapting does Adapter do?

• Adapter와 Adaptee 간의 inteface 차이 정도에 따라 작업의 수준이달라짐.

l Trade-offs of Class and Object adapters

l 구현l Implementing class adapters in C++

• 일반적으로 Adapter class 가 Target class는 public으로, Adaptee class는 private으로 상속 받는다.

34

Page 35: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

어뎁터 패턴: 사례 #1

l 그래픽 에디터 프로그램l 그래픽 객체로 Line 과 Text 가 존재한다.l TextShape 구현이 복잡한 관계로 기존에 존재하는 TextView 클래스 사

용.

Target Adaptee

35 Adapter

Page 36: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

어뎁터 패턴: 사례 #1

l Shape, TextView code

class Shape {public:

Shape();virtual void BoundingBox(Point& bottomLeft, Point& topRight) const;virtual Manipulator* CreateManipulator() const;

};

class TextView {public:

TextView();void GetOrigin(Coord& x, Coord& y) const;void GetExtent(Coord& width, Coord& height) const;virtual bool IsEmpty() const;

};

36

class Shape {public:

Shape();virtual void BoundingBox(Point& bottomLeft, Point& topRight) const;virtual Manipulator* CreateManipulator() const;

};

class TextView {public:

TextView();void GetOrigin(Coord& x, Coord& y) const;void GetExtent(Coord& width, Coord& height) const;virtual bool IsEmpty() const;

};

Page 37: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

어뎁터 패턴: 사례 #1

l Class Adapter 방식으로 구현

class TextShape : public Shape, private TextView {public:

TextShape();

virtual void BoundingBox( Point& bottomLeft, Point& topRight ) const;virtual bool IsEmpty() const;virtual Manipulator* CreateManipulator() const;

};

void TextShape::BoundingBox ( Point& bottomLeft, Point& topRight ) const {Coord bottom, left, width, height;

GetOrigin(bottom, left);GetExtent(width, height);bottomLeft = Point(bottom, left);topRight = Point(bottom + height, left + width);

}

Target은 public, Adaptee는 private

37

class TextShape : public Shape, private TextView {public:

TextShape();

virtual void BoundingBox( Point& bottomLeft, Point& topRight ) const;virtual bool IsEmpty() const;virtual Manipulator* CreateManipulator() const;

};

void TextShape::BoundingBox ( Point& bottomLeft, Point& topRight ) const {Coord bottom, left, width, height;

GetOrigin(bottom, left);GetExtent(width, height);bottomLeft = Point(bottom, left);topRight = Point(bottom + height, left + width);

}

Adaptee(TextView) 함수 호출

Page 38: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

어뎁터 패턴: 사례 #1

l Object Adapter 방식으로 구현

class TextShape : public Shape {public:

TextShape(TextView*) {_text = t;

}virtual void BoundingBox( Point& bottomLeft, Point& topRight ) const;virtual bool IsEmpty() const;virtual Manipulator* CreateManipulator() const;

private:TextView* _text;

};

void TextShape::BoundingBox ( Point& bottomLeft, Point& topRight) const {Coord bottom, left, width, height;

_text->GetOrigin(bottom, left);_text->GetExtent(width, height);

bottomLeft = Point(bottom, left);topRight = Point(bottom + height, left + width);

}

Adaptee(TextView) 객체 지정

38

class TextShape : public Shape {public:

TextShape(TextView*) {_text = t;

}virtual void BoundingBox( Point& bottomLeft, Point& topRight ) const;virtual bool IsEmpty() const;virtual Manipulator* CreateManipulator() const;

private:TextView* _text;

};

void TextShape::BoundingBox ( Point& bottomLeft, Point& topRight) const {Coord bottom, left, width, height;

_text->GetOrigin(bottom, left);_text->GetExtent(width, height);

bottomLeft = Point(bottom, left);topRight = Point(bottom + height, left + width);

}

지정된 Adaptee 객체 함수호출

Page 39: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

Pattern #10 – 프록시 패턴

l 패턴 요약l 특정 객체에 접근을 조절하기 위하여 대리자(프록시)를 세움l 필요할 때만 비싼 대가의 기능을 접근하도록 프록시를 사이에 둠

시간이 많이 소요되는 불필요한 복잡한 객체를 생성하는

시간을 간단한 객체로 줄임

39

시간이 많이 소요되는 불필요한 복잡한 객체를 생성하는

시간을 간단한 객체로 줄임

Page 40: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

프록시 패턴: 동 기

당신이 이번에 참여한 프로젝트는 그래픽을 지원하는 문서편집기를업그레이드하는 작업이다. 사용자들이 기존의 문서편집기를 사용할 때 가장큰 불만사항은 파일을 여는데 속도가 너무 느리다는 점이다. 이유를분석해보니 파일을 열 때 문서에 포함된 그림들을 모두 메모리에 올리고, 또압축된그림데이터를 Bitmap으로변환하는작업을수행하기때문이다.문서의 모든 그림들을 사용자가 보는 경우는 드물다는 점을 이용해서,사용자가 실제로 보는 그림(화면에 출력을 요구 받은 그림 객체) 들만메모리에 올린다면, 파일 여는 시간을 훨씬 단축시킬 수 있을 것이다. 기존의설계를어떻게변경해야될까?

당신이 이번에 참여한 프로젝트는 그래픽을 지원하는 문서편집기를업그레이드하는 작업이다. 사용자들이 기존의 문서편집기를 사용할 때 가장큰 불만사항은 파일을 여는데 속도가 너무 느리다는 점이다. 이유를분석해보니 파일을 열 때 문서에 포함된 그림들을 모두 메모리에 올리고, 또압축된그림데이터를 Bitmap으로변환하는작업을수행하기때문이다.문서의 모든 그림들을 사용자가 보는 경우는 드물다는 점을 이용해서,사용자가 실제로 보는 그림(화면에 출력을 요구 받은 그림 객체) 들만메모리에 올린다면, 파일 여는 시간을 훨씬 단축시킬 수 있을 것이다. 기존의설계를어떻게변경해야될까?

40

당신이 이번에 참여한 프로젝트는 그래픽을 지원하는 문서편집기를업그레이드하는 작업이다. 사용자들이 기존의 문서편집기를 사용할 때 가장큰 불만사항은 파일을 여는데 속도가 너무 느리다는 점이다. 이유를분석해보니 파일을 열 때 문서에 포함된 그림들을 모두 메모리에 올리고, 또압축된그림데이터를 Bitmap으로변환하는작업을수행하기때문이다.문서의 모든 그림들을 사용자가 보는 경우는 드물다는 점을 이용해서,사용자가 실제로 보는 그림(화면에 출력을 요구 받은 그림 객체) 들만메모리에 올린다면, 파일 여는 시간을 훨씬 단축시킬 수 있을 것이다. 기존의설계를어떻게변경해야될까?

당신이 이번에 참여한 프로젝트는 그래픽을 지원하는 문서편집기를업그레이드하는 작업이다. 사용자들이 기존의 문서편집기를 사용할 때 가장큰 불만사항은 파일을 여는데 속도가 너무 느리다는 점이다. 이유를분석해보니 파일을 열 때 문서에 포함된 그림들을 모두 메모리에 올리고, 또압축된그림데이터를 Bitmap으로변환하는작업을수행하기때문이다.문서의 모든 그림들을 사용자가 보는 경우는 드물다는 점을 이용해서,사용자가 실제로 보는 그림(화면에 출력을 요구 받은 그림 객체) 들만메모리에 올린다면, 파일 여는 시간을 훨씬 단축시킬 수 있을 것이다. 기존의설계를어떻게변경해야될까?

사용자가 한번도 안보고 문서를 닫을 수도 있는데미리 그림 객체를 만들 필요가 있을까?

this is the first you

r testing about the

airplains this is

the first your

testing about the airplains

this is the first te

sting a this

is is the first testing about

실제 화면에 출력할 필요가 있는 그림 객체만 생성

Page 41: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

프록시 패턴: 동 기

l 기존 설계

// Client Code

Document *doc = new Document;…doc->Insert(new Image(“chart1.jpg”));…doc->drawPage(0); // draws the first page

image 객체 생성

41

// Client Code

Document *doc = new Document;…doc->Insert(new Image(“chart1.jpg”));…doc->drawPage(0); // draws the first page

어떻게 하면 Image 객체 생성을 해당객체가 필요할 때까지 미룰 수 있을까? 어떻게 하면 Image 객체 생성을 해당

객체가 필요할 때까지 미룰 수 있을까?

Page 42: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

프록시 패턴: 동 기

l 해결방안l 대리자(Proxy, Agent) 를 내세우기l proxy는 기존의 코드에서 image 객체를 대신함l proxy는 요청을 받으면, 자신이 대신하고 있는 image객체에 해당 요청을 보냄l proxy 객체가 처음 생성될 때는 자신이 대신할 image객체를 미리 만들지 않고,

외부에서 처음 요청이 들어왔을 때(즉, image 객체가 필요할 때) image 객체를생성.

this is the first te

sting a this

is is the first testing about

42

this is the first you

r testing about the

airplains this is

the first your

testing about the airplains

this is the first te

sting a this

is is the first testing about

aImageProxy

aImageProxy

aImageProxy

aImageProxy

aImageProxy

aImage

this is the first you

r testing about the

airplains this is

the first your

testing about the airplains

this is the first te

sting a this

is is the first testing about

aImageProxy

aImageProxy

aImageProxy

aImageProxy

aImageProxy

aImage

aImage

생성

Page 43: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

프록시 패턴: 동 기

l Class diagram

43

// Client Code

Document *doc = new Document;…doc->Insert(new ImageProxy(“chart1.jpg”));…doc->drawPage(0); // draws the first page

Image 객체 대신ImageProxy 객체 사용

Page 44: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

프록시 패턴

l 의도l 특정 객체에 대한 접근(access)을 조절하기 위하여 대리자를 둔다.

l 별명l Surrogate

l 적용 범위l remote proxy: 다른 주소에 존재, 다른 공간에 존재하는 객체에 대한 로

컬 표현l virtual proxy: 복잡한 객체를 필요할 때 생성l protection proxy: 원래 객체에 대한 억세스 권한을 제한l smart reference: 객체접근 시 추가적인 액션 수행. 참조회수를 관리하거

나 객체를 수정할 수 없도록 locking

l 의도l 특정 객체에 대한 접근(access)을 조절하기 위하여 대리자를 둔다.

l 별명l Surrogate

l 적용 범위l remote proxy: 다른 주소에 존재, 다른 공간에 존재하는 객체에 대한 로

컬 표현l virtual proxy: 복잡한 객체를 필요할 때 생성l protection proxy: 원래 객체에 대한 억세스 권한을 제한l smart reference: 객체접근 시 추가적인 액션 수행. 참조회수를 관리하거

나 객체를 수정할 수 없도록 locking

44

Page 45: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

프록시 패턴

l 구 조

l [객체다이어그램]

l 구 조

l [객체다이어그램]

45

aClientsubject aProxy

subject aRealSubject

Page 46: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

프록시 패턴

l 구성요소l Proxy(ImageProxy)

• RealSubject 객체에 대한 reference 를 유지한다.• Subject interface를 구현하여 RealSubject 객체를 대신할 수 있다.• RealSubject 객체에 대한 접근을 조절하며, 해당 객체의 생성과 소멸

을 책임질 수 도 있다.l Subject(Graphic)

• RealSubject 와 Proxy의 공통 interface를 정의한다.l RealSubject(Image)

• Proxy가 대신할 실제 객체를 정의한다.

l 협동l Proxy는 client의 요청을 RealSubject 객체에게 보낸다.

l 구성요소l Proxy(ImageProxy)

• RealSubject 객체에 대한 reference 를 유지한다.• Subject interface를 구현하여 RealSubject 객체를 대신할 수 있다.• RealSubject 객체에 대한 접근을 조절하며, 해당 객체의 생성과 소멸

을 책임질 수 도 있다.l Subject(Graphic)

• RealSubject 와 Proxy의 공통 interface를 정의한다.l RealSubject(Image)

• Proxy가 대신할 실제 객체를 정의한다.

l 협동l Proxy는 client의 요청을 RealSubject 객체에게 보낸다.

46

Page 47: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

프록시 패턴

l 결과l remote proxy는 객체가 다른 주소공간에 존재하는 사실을 숨길 수 있게

한다.l virtual proxy는 객체를 필요할 때 생성하여 최적화를 수행한다.l protection proxy와 smart reference는 객체가 접근할 때 추가적인

housekeeping 작업을 수행한다.l 불필요한 다운로드 또는 heavy work을 피한다.

47

Page 48: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

프록시 패턴

l 구현l 접근 연산자 (‘->’ in C++) 를 재정의하기

• RealSubject 객체 접근에 대한 조정기능을 각 함수마다 넣는 것이 아니라, 접근 연산자를 재정의하여 여기에 넣는다.

l Proxy 객체가 항상 RealSubject의 class를 알고 있을 필요는 없다.• Proxy 객체가 RealSubject 객체를 직접 접근하지 않고, Subject

interface를 사용하여 객체를 다룸으로써 범용적인 Proxy로 만들 수있다.

l 구현l 접근 연산자 (‘->’ in C++) 를 재정의하기

• RealSubject 객체 접근에 대한 조정기능을 각 함수마다 넣는 것이 아니라, 접근 연산자를 재정의하여 여기에 넣는다.

l Proxy 객체가 항상 RealSubject의 class를 알고 있을 필요는 없다.• Proxy 객체가 RealSubject 객체를 직접 접근하지 않고, Subject

interface를 사용하여 객체를 다룸으로써 범용적인 Proxy로 만들 수있다.

48

Page 49: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

프록시 패턴: 사례 #1

[접근 연산자 재정의 사례 코드]

class Image;// external functionextern Image* LoadAnImageFile(const char*);

class ImagePtr {public:

ImagePtr (const char* theImageFile) {_imageFile = theImageFile;_image = 0;

}virtual ~ImagePtr();virtual Image* operator->() { return LoadImage(); }virtual Image& operator*() { return *LoadImage(); }

private:Image* LoadImage() {

if (_image == NULL) _image = LoadAnImageFile(_imageFile);

return _image;}

private:Image* _image;const char* _imageFile;

};

// Client Code

ImagePtr image = ImagePtr(“chart1.jpg”);image->Draw(100,100);// same as (image.operator->()) ->Draw(100,100);

pointer가 아닌 image가마치 Image 객체의pointer처럼 사용

49

class Image;// external functionextern Image* LoadAnImageFile(const char*);

class ImagePtr {public:

ImagePtr (const char* theImageFile) {_imageFile = theImageFile;_image = 0;

}virtual ~ImagePtr();virtual Image* operator->() { return LoadImage(); }virtual Image& operator*() { return *LoadImage(); }

private:Image* LoadImage() {

if (_image == NULL) _image = LoadAnImageFile(_imageFile);

return _image;}

private:Image* _image;const char* _imageFile;

};

// Client Code

ImagePtr image = ImagePtr(“chart1.jpg”);image->Draw(100,100);// same as (image.operator->()) ->Draw(100,100);

reference, dereference 연산자 재 정의

Page 50: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

프록시 패턴

l 사례 코드l 문제 해결방안에 대한 소스코드

class Graphic {public:

virtual ~Graphic();virtual void Draw(const Point& at) = 0;virtual const Point& GetExtent() = 0;virtual void Load(istream& from) = 0;virtual void Save(ostream& to) = 0;

protected:Graphic();

};

class Image : public Graphic {public:

Image(const char* file); // loads image from a filevirtual ~Image();virtual void Draw(const Point& at);virtual const Point& GetExtent();virtual void Load(istream& from);virtual void Save(ostream& to);

private:// ...

};50

class Graphic {public:

virtual ~Graphic();virtual void Draw(const Point& at) = 0;virtual const Point& GetExtent() = 0;virtual void Load(istream& from) = 0;virtual void Save(ostream& to) = 0;

protected:Graphic();

};

class Image : public Graphic {public:

Image(const char* file); // loads image from a filevirtual ~Image();virtual void Draw(const Point& at);virtual const Point& GetExtent();virtual void Load(istream& from);virtual void Save(ostream& to);

private:// ...

};

Page 51: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

프록시 패턴class ImageProxy : public Graphic {public:

ImageProxy(const char* fileName) {_fileName = strdup(fileName);_extent = Point::Zero; // don't know extent yet_image = NULL;

}virtual ~ImageProxy();virtual void Draw(const Point& at) {

GetImage()->Draw(at);}virtual const Point& GetExtent() {

if (_extent == Point::Zero) _extent = GetImage()->GetExtent();

return _extent;}virtual void Load(istream& from);virtual void Save(ostream& to);

protected:Image* GetImage() {

if (_image == 0) _image = new Image(_fileName);

return _image;}

private:Image* _image;Point _extent;char* _fileName;

};

class Document {public:

Document();~Document(); //void Insert(Graphic*);// ...

};

// Client CodeDocument* doc = new Document;// ...doc->Insert(new ImageProxy(“chart1.jpg"));

51

class ImageProxy : public Graphic {public:

ImageProxy(const char* fileName) {_fileName = strdup(fileName);_extent = Point::Zero; // don't know extent yet_image = NULL;

}virtual ~ImageProxy();virtual void Draw(const Point& at) {

GetImage()->Draw(at);}virtual const Point& GetExtent() {

if (_extent == Point::Zero) _extent = GetImage()->GetExtent();

return _extent;}virtual void Load(istream& from);virtual void Save(ostream& to);

protected:Image* GetImage() {

if (_image == 0) _image = new Image(_fileName);

return _image;}

private:Image* _image;Point _extent;char* _fileName;

};

class Document {public:

Document();~Document(); //void Insert(Graphic*);// ...

};

// Client CodeDocument* doc = new Document;// ...doc->Insert(new ImageProxy(“chart1.jpg"));

Page 52: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

프록시 패턴: 사례 #2

l 프록시 프린터

52

Page 53: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

Proxy Example TelNumsvalue: Vector

getTelNums(): VectorshowMiddleRecord()

RemoteTelNumsgetTelNums()

TelNumsProxygetTelNums()

TelephoneAppdisplay( TelNums )

display MiddleRecord()

remoteTelNums

static

1

53

RemoteTelNumsgetTelNums()

TelNumsProxygetTelNums()

. . . // One way to check if really needed:if ( value == null ) // never referenced

remoteTelNums.getTelNums(); else // no need to call ‘getTelNums()’

SetupEnsures that TelephoneAppmakes calls with TelNumsProxyinstance

Page 54: 객체지향설계와패턴 Lecture #11: 구조패턴(2) · Pattern #8 –컴포지트패턴 l패턴요약 l기본클래스와이를포함하는컨테이너클래스를재귀적인형태로표현

237점157점464점

Questions?

237점157점464점

Questions?