적응자( Adapter )

Posted 2012. 10. 22. 17:41
한 클래스의 인터페이스를 호환 가능한 가른 인터페이스로 변환시키는 디자인 패턴.


사용예)
1. 기존의 클래스를 재사용 하고 싶지만 인터페이스가 맞지 않을때
2. 인터페이스가 다른 클래스들을 묶어서 함께 동작하도록 하고 싶을때
3. 인터페이스가 다른 클래스와 그 서브 클래스들을 모두 재사용하고 싶을 때



적응자 패턴엔 두가지 종류가 있다.

1. 객체 어댑터 패턴 Object Adapter Pattern

이 타입의 어댑터 패턴에서 어댑터는 감싸야할 클래스의 객체를 포함하고 있다.

이러한 상황에서 어댑터는 감싸진 객체를 호출하는 일을 한다.

집합관계를 이용한 새로운 객체를 두는 방식.

기존 클래스의 함수를 오버라이드 할 수 없다.


ex) 여러 직업이 있다. 전사, 마법사, 힐러 등등, 전사도 Level 1짜리 힐 능력을 주고 싶은데

인터페이스가 다른게 문제다. 

class AidKid

{

};


class Fighter

{

private:

public:

virtual void cure(AidKit *) = 0;

virtual void attack() = 0;

virtual void defense() = 0;

void cFighter(){ cout << "class figher" << endl; }

};


class Healer

{

public:

void healing(int Level)

{

cout << "Level : " << Level << "Healing 시전" << endl;

}

void magic_attack();

void magic_defense();

};


class AdvFighter : public Fighter

{

private:

Healer *heal;

int healLevel;


public:

AdvFighter(Healer *h)

{

heal = h;

healLevel = 1;

}

void attack(){ cout << "Attack" << endl; }

void defense(){ cout << "Defense" << endl; }

void setHealLevel( int Lev ){ }

// 레벨업 되면서 힐러의 healing 마법을 쓸수 있게 되었다.

// 기존의 붕대 스킬은 그대로 둔채 새로운 스킬을 추가해도 된다

void cure( AidKit *)

{

heal->healing(healLevel);

}

void healing()

{

heal->healing(healLevel);

}

int getHealLevel()

{

return healLevel;

}

}


void main()

{

Healer *myHealer = NULL;

AidKit *myKit = NULL;

AdvFighter *healFighter = new AdvFigher( myHealer );

healFighter->cFighter();

healFighter->cure(myKit);

healFighter->healing();

healFighter->attack();

delete healFighter;

}




2. 클래스 어댑터 패턴 Class Adapter Pattern

이 타입의 어댑터는 목표를 달성하기 위해 여러개의 다형성 인터페이스( ploymorphic interfaces)를 사용 한다. 어댑터는 구현될 예정인 인터페이스나 이미 구현된 인터페이스를 상속 받아서 만들어진다.

구현될 예정인 인터페이스는 순수인터페이스 클래스로 만들어지는 것이 일반적이다.

즉. 다중상속을 사용하여 인터페이스를 변경한다.

오버라이드 할 수 있다.


class AidKit

{

};


class Fighter

{

private:

public:

virtual void cure(AidKit *) = 0;

virtual void attack() = 0;

virtual void defense() = 0;

void myClass(){ cout << "I'm Fighter" << endl; }

};


class Healer

{

public:

void healing( int Level )

{

cout << "Level : " << Level << "Healing 시전" << endl;

}

void magic_attack();

void magic_defense();

};

class AdvFighter : public Fighter, private Healer

{

private:

int healLevel;

public:

AdvFighter()

{

healLevel = 1;

}

void cure(AidKit *)

{

Healer::healing(healLevel);

}

void attack(){}

void defense(){}

};

void main()

{

AdvFighter *myFighter = new AdvFighter;

AidKit *myKit = NULL;

myFighter->myClass();

myFighter->cure(myKit);

delete myFighter;

}


원형( Prototype )

Posted 2012. 10. 22. 17:38

프로토타입 패턴?

객체에 의해 생성될 객체의 타입이 결정되는 생성 디자인 패턴.

이 패턴은 새로운 객체를 생성하기 위해 clone(복제)를 이용 한다.

클라app에서 객체 생성자의 서브 클래싱을 피한다.(추상팩토리는 객체 생성자를 서브클래싱해야한다)

주어진 app에서 일반적인 방법( new 키워드를 이용한 방법)으로 객체를 생성할 때에 필요한 비용이

엄청난 경우에 이 비용을 없앨 수 있다.


이 패턴을 구현하기 위해 순수가상 clone()메서드를 가지는 추상 클래스를 선언한다.

다형적인 생성자( polymorphic constructor )가 필요한 어떤 클래스든지 추상 클래스를 상속받아서

clone()메서드를 구현 해야 한다.( 원형 객체를 생선하는 초기화 동작이 꼭 필요하다)

클라는 new 연산자와 클래스 이름을 같이 쓰기보다 프로토타입 객체의 clone()메서드를 호출 하거나

팩토리에 원하는 클래스에 해당하는 인자를 넣어서 호출하거나, 다른 디자인 패턴에 의해 제공 되는

어떤 매커니즘을 통해 clone()메서드를 호출 할 수도 있다.


사용 예)

제품의 생성, 복합, 표현 방법에 독립적인 제품을 만들고자 할때.

어떤 클래스의 인스턴스를 만드는 것이 자원/시간을 많이 잡아먹거나 복잡 할 때.

모두 클래스로 만들기에 종류가 너무 많을때

인스턴스 생성이 어려운 경우( 인스턴스화할 클래스를 런타임에 지정할때, 동적 로딩)


구조.


약간의 설정 변경으로 비슷하지만 다른 클래스로의 확장이 가능한 경우, 세부 클래스를 미리 명세하지 않고 런타임에 원형을 복제해서 그 복사본을 수정함으로써 동적 클래스 생성을 가능케 하는 패턴이다.


원형 패턴과 추상 팩토리 패턴은 어떤 면에선 경쟁적인 관계다. 하지만 함께 사용 할 수도 있다.



// Prototype

class Prototype

{

public:

virtual ~Prototype() {}

virtual Prototype* clone() const = 0;

};


// Concreate Prototype

class ConcreatePrototype : public Prototype

{

public:

ConcreatePrototype( int x ) : x_(x) {}

ConcreatePrototype( const CroncreatePrototype& p) : x_(p.x_){}

virtual Prototype* clone() const{ return new ConcreatePrototype(*this); }

void setX( int x ) { x_ = x; }

int getX() const { return x_; }

void printX() const{ std::cout<< "Value : " << x_ << std::endl; }

private:

int x_;

};


// client

void main()

{

Prototype* prototype = new ConcreatePrototype(1000);

for( int i = 1 ; i < 10 ; i++ )

{

CreatePrototype* tempotype =

dynamin_case<ConcreatePrototype*>(prototype->clone());

tempotype->setX(tempotype->getX() * i );

tempotype->printX();

delete tempotype;

}

delete prototype;

}


-> valuie : 1000

-> value : 2000

-> value : 3000

..

..

..

-> value : 9000

팩토리 메서드( Factory Method )

Posted 2012. 10. 22. 16:57
팩토리 메서드란?
객체의 생성에 관련된 인터페이스를 정의하고 인터페이스를 구현하는 클래스에서 어떤 클래스를

인스턴스화(생성) 할 것인지를 정하게 두는 것.

서브플래스에서 인스턴스화를 하도록 미루를 것


특징)

팩토리 메서는 객체의 생성을 캡슐화 한다. 이는 생성 절차가 매우 복잡한 경우에 유용하다.



사용예)

라이브러리 코드, 프레임 웍 등등.

한 객체의 생성이 코드의 중복없이 재사용 하는 것을 못하도록 하는 상황

한 객체의 생성이 결합하는(사용하는) 클래스에서 필요하지 않은 정보다 리소스에 접근 해야 할때.

App에서 일관성 있는 동작을 하기 위해 생성된 객체의 살아있는 시간(lifetime)의 관리가 

중앙에서 관리할 필요가 있을 때.


단점 )

팩토리를 사용하기 위해 기존 클래스를 리펙토링 하는 것이 기존 클라의 코드를 깬다는 점.

private생성자를 사용 하기 때문에 해당 클래스를 확장 할 수 없다(상속받을수 없다)

-> 서브클래스는 상속받은 생성자를 호출해야하지만, 생성자가 private이라면,,불가능함

만약 그 클래스를 확장 한다면( ex)생성자를 protected로 만듬) 서브 클래스는 부모가 가지고 있는

모든 팩토리 메서드를 재구현 하지 않으면 서브클래스의 객체가 생성되는게 아니라 부모클래스의 객체가 생성된다..

« PREV : 1 : ··· : 37 : 38 : 39 : 40 : 41 : 42 : 43 : ··· : 77 : NEXT »