플라이급( Flyweight )

Posted 2012. 10. 23. 16:44

중복 되는 객체의 본질 공유 패턴


Mon Mon Mon Mon Mon

Missile Missile Missile

맵에 몬스터가 나오고 미사일을 쏜다.

몬스터 3마리는 모두 외관이 동일하고, 동작에 대한 표현이 같은데

그것을 포함한 객체를 몬스터 숫자만큼 생성하는건 너부 비효율 적이다.

이 본질적 요소를 기준으로 공유될 수 있는 객체를 분류하는 것이 플라이급 패턴.


클래스의 경량화를 목적으로 다수의 객체로 생성 될 경우 모두가 갖는 본질적인 요소를 클래스화 하여

공유함으로써 메모리 절감의 효과를 보는 패턴. 부가적인 요소는 사용자가 관리하며 그 요소를 플라이

급 객체에서 매개변수로 받아 본질 요소를 이룔 할 수 있다.


이건 뭐.. 옜날에 매니저 클래스 들이네 ㅡ,.ㅡ


알게 모르게 고민하고 짯던 부분들이 다 패턴들이었군 ㅇ,.ㅇ

퍼사드( Facade )

Posted 2012. 10. 23. 16:13

복잡한 서브 시스템을 간단하게 사용하기 위한 패턴.

인터페이스를 앞에 제공해 주는 패턴.


파란선 참고 ↗

상용 단계가 아니라 개발자가 조작하듯 직접 구성요소들을 조작 해야 한다.

사용자는 냄비를 할당하고 물을 끓인 후 튀긴 면발을 할당하여 면을 넣고 부재료도 할당하여

직접 넣어야 한다. 이 모든 과정을 사용자가 직접해야 한다. 개발자는 수월하겠지만

일반 사용자는 이런 복잡한 상태라면 먹지 않을 것이다.


위 그림처럼 됬을 경우. 뭔가 되게 불편하고, 냄비의 구조나 면발의 사용법이 달라졌을때 이전 사용법

으로 조작하면 꼼짝없이 사용시 오류가 나버린다.이런 불편을 해소하고 객체에 사용자에 대한 강한

결합도를 낮추기 위해 인터페이스를 두는 것이 퍼사드 패턴 이다.



사용자는 라면 자판기에 원하는 면발과 부재료만 누르면 알아서 라면이 나온다.

복잡한 구조를 몰라도 사용하는데 무리가 없다.


위 패턴은 Builder패턴과 상당히 유사하다.

하지만 빌더는 생성의 구성 순서를 정하여 생성 전용으로 쓰는 패턴이고

퍼사드는 생성 뿐만 아니라 내부의 다른 기능들까지 인터페이스 역할을 해낼 수 있다.

예를 들면 라면 생성뿐만 아니라 라면 잔여물 처리나 라면 추가 같은 기능도 넣을 수 있다.


퍼사드에선 각 객체들로 단방향으로 설계가 되어있기 때문에 자연스럽게 결합도가 낮아지고,

서브 클래스 추가나 변경에 더 유연하게 대철 할 수 있는 것이다.

이런 식은 우리도 많이 쓰곤 한다. 필요한 각종 기능들을 한 클래스의 함수에 몰아서 한번에 쫙 호출

하는 그런 패턴, 그런 인터페이스의 단순화가 많아질수록 시스템에 대한 접근성이 높아지고 단위별로

테스트가 가능하기 때문에 오류에 대한 처리도 상당히 유리하게 된다.


정리하면

퍼사드 패턴은 복잡한 시스템에 대하여 단순한 인터페이스를 제공함으로써 사용자와 시스템 간, 또는

여타 시스템과의 결합도를 낮춰주고, 시스템 구조에 대한 파악이 쉬워지는 패턴이다.

오류에 대해 단위별로 확인 할 수 있고, 사용자에게 단순한 인터페이스를 제공함으로써 접근성을 높임.



#include <iostream>

using namespace std;


// 면발 클래스

class Noodle

{

public:

virtual Noodle* NoodleInsert() = 0; // 면 넣기

virtual void Print() = 0; // 면 정보 출력

};


// 생서 면발 클래스

class LiveNoodle : public Noodle

{

public:

virtual Noodle* NoodleInsert()

{

cout << "생성 면발을 넣습니다" << endl;

return this;

}

virtual void Print()

{

cout << "생성 면발";

}

};


// 튀김 면발 클래스

class FriendNoodle : public Noodle

{

public:

virtual Noodle* NoodleInsert()

{

cout << "튀김 면발으 넣습니다" << endl;

return this;

}

virtual void Print()

{

cout << "뒤김 면발";

}

};


// 부재료 클래스

class SubMaterial

{

public:

virtual SubMaterial* SubMaterialInsert() = 0; // 부재료 넣기

virtual void Print() = 0; // 재료 출력

};


// 치즈 클래스

class Cheese : public SubMaterial

{

public:

virtual SubMaterial* SubMaterialInsert()

{

cout << "치즈를 넣습니다" << endl;

return this;

}

virtual void Print()

{

cout << "치즈 ";

}

};


// 만두 클래스

class Dumpling : public SubMaterial

{

public:

virtual SubMaterial* SubMaterialInsert()

{

cout << "만두를 넣습니다" << endl;

return this;

}

virtual void Print()

{

cout << "만두 ";

}

};


// 냄비 클래스

class Pot

{

private:

Noodle *noodle;

SubMaterial *Material;

public:

Pot()

{

noodle = NULL;

Material = NULL;

}

~Pot()

{

if( noodle )

delete noodle;

if( Material )

delete Material;

}

public:

void Boil() // 물끓이기

{

cout << "냄비에 물을 끓입니다" << endl;

}

void InsertNoodle( Noodle *noodle) // 면발 넣기

{

this->noodle = noodle;

}

void InsertMaterial( SubMaterial *Material ) // 재료 넣기

{

this->Material = Material;

}

void Print() // 라면 정보 출력

{

noodle->Print();

Material->Print();

cout << "라면 입니다" << endl;

}

};


// 라면 자판기 클래스

class RamenMachine

{

public:

void Cooking( Pot *pot, Noodle *noodle, SubMaterial *Material )

{

pot->Boil();

pot->InsertNoodle(noodle->NoodleInsert());

pot->InsertMaterial( Material->SubMaterialInsert() );

cout << "조리가 완료 되었습니다" << endl;

}

};


void main()

{

RamenMachine Machine;

Pot *pot = new Pot;

Machine.Cooking( pot, new LiveNoodle, new Dumpling );


cout << endl <<"--라면 정보--" << endl;

pot->Print();


delete pot;

}

-> 냄비에 물을 끓입니다
-> 생성 면발을 넣습니다
-> 만두를 넣습니다
-> 조리가 완료 되었습니다
->--라면정보--
->생성 면발만두 라면 입니다


장식자( Decorator )

Posted 2012. 10. 23. 15:34

클래스 기능의 동적인 추가를 가능하게 하는 구조 !!

클래스의 기능이 추가된 확장 클래스 객체 생성을 런타임에 동적으로 할 수 있게 하는 패턴

장식적인 의미의 추가 기능들과 오리지널 클래스를 분리하여 합성 객체에 대한 융통성을 제공함.

하지만 장식이 될 객체의 최상위 부모 클래스는 작고 가벼워야 효율적이다. 왜냐면

장식이 중복된 규모있는 클래스를 객체화 할 경우 부모의 크기에 따라 객체의 크기가 커지고

기능적으로 장식자에 부담으로 작용 되기 때문.

중간 클래스로 Decorator를 두는 것이 좋다. 두지 않으면 최상위 클래스가 Deco객체도 관리하게 

되므로 Deco객체만의 Interface를 가질 수 없게 된다.

Decorator클래스는 구현될 일이 없으므로 abstract class로 둔다.


사용 예)

게임 플레이 도중 새로운 아이템을 추가 시키거나 삭제 시킬때.

오락실 비행기 게임, 아이템 먹을수록 미사일 파워 증가.

처럼 다른객체에 영향을 주지 않고 객체에 기능을 추가하고 싶을때

상속을 통한 기능확장이 어려울때.


단점.

( 장식자 개수 * 부모 클래스 크기 ) 만큼 객체 하나의 부담이 증가한다.

장식자나 오리지널 객체 자체가 가벼워져서 그 의미가 뚜렷하지 않으면 그 수가 많아질경우

관리가 힘들어진다.


전략(Strategy) 패턴과의 비교.

객체의 내부가 아닌 외부적인 기능의 추가에 적합것이 장식자 패턴

배주 자체에 기능의 변경이라던지 추가에는 전략 패턴이 적합.

전략 패턴은 직접 오리지널과 같은 부모를 상속받는 것이고 따로 기능만 정의해서 오리지널을 참조를 통해 접근 하는 패턴.



#include <iostream>

using namespace std;


// 최상위 순수 가상. 작고 가벼워야 효율적

//인간클래스

class Human

{

public:

virtual ~Human(){};

public:

virtual void Draw() = 0;

};


// 여자 클래스

class Girl : public Human

{

public:

virtual void Draw()

{    

cout << "여자 출력" << endl;

}

};


// 장식 클래스

class Decorator : public Human

{

protected:

Human *ori;

public:

Decorator( Human *ori )

{

this->ori = ori;

}

virtual ~Decorator()

{

delete ori;

}

public:

virtual void Draw()

{

ori->Draw();

}

};


// 귀걸이 ㅡㄹ래스

class Earring : public Decorator

{

public:

Earring( Human *ori ) : Decorator( ori )

{

}

virtual void Draw()

{

Decorator::Draw();

cout << "귀걸이 출력" << endl;

}

};


// 안경 클래스

class Glass : public Decorator

{

public:

Glass( Human *ori ) : Decorator( ori )

{

}

virtual void Draw()

{

Decorator::Draw();

cout << "안경 출력" << endl;

}

};


void main()

{

cout << "---안경 여자 ---" << endl;

Human *girl = new Girl;

Human *GlassGirl = new Glass( girl );    // 안경 여자

GlassGirl->Draw();


cout << endl;


cout << "---안경 귀걸이 여자---" << endl;

Human *girl2 = new Girl;

Human *GlassEarringGirl = new Glass( new Earring( girl2) );    // 안경 귀걸이 여자

GlassEarringGirl->Draw();


delete GlassGirl;

delete GlassEarringGirl;

}

-> --- 안경 여자 ---

-> 여자 출력

-> 안경 출력

-> --- 안경 귀걸이 여자 ---

-> 여자 출력

-> 귀걸이 출력

-> 안경 출력

« PREV : 1 : ··· : 35 : 36 : 37 : 38 : 39 : 40 : 41 : ··· : 77 : NEXT »