퍼사드( 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;

}

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