의도

  • 한 서스시스템 내의 인터페이스 집합에 대한 획일화된 하나의 인터페이스를 제공하는 패턴으로, 서브시스템을 사용하기 쉽도록 상위 수준의 인터페이스를 정의함.

 

언제 쓰는가?

  • 복잡한 서브시스템에 대한 단순한 인터페이스 제공이 필요할 때.
    • 시스템 범위가 확장되면, 또한 구체적으로 설계되면 서브시스템은 계속 복잡해짐.
    • 서브시스템에 대한 단순한 인터페이스를 제공하며 개발자에게 적합한 클래스 형태를 제공함.
  • 추상 개념에 대한 구현 클래스와 사용자 사이에 너무 많은 종속성이 존재할 때.
    • 퍼사드를 사용하여 사용자와 다른 서브시스템 간 결합도를 줄일 수 있음.
  • 서브시스템을 계층화시킬 때.
    • 퍼사드 패턴을 사용하여 서브시스템에 대한 접근점을 제공함.
    • 서브시스템이 다른 서브시스템에 종속적이라 하더라도, 퍼사드를 통해서만 대화를 진행하게 함으로써 종속성을 줄일 수 있음.

 

구조

GoF의 디자인 패턴 중 P.256

  • Facade : 단순하고 일관된 통합 인터페이스를 제공하며, 서브시스템을 구성하는 어떤 클래스가 어떤 요청을 처리해야 하는지 알고 있으며, 사용자의 요청을 해당 서브시스템 객체에 전달함.
  • 서브시스템 클래스들 : 서브시스템의 기능을 구현하고, Facade 객체로 할당된 작업을 실제로 처리하지만 Facade에 대한 아무런 정보가 없음.

 

협력 방법

  • 사용자는 Facade에 정의된 인터페이스를 이용해서 상호작용함. 서브시스템을 구성하는 객체가 실제의 요청 처리를  담당하지만 퍼사드는 서브시스템에게 메시지를 전달하기 위해 자신의 인터페이스에 동일한 작업을 정의해야 함.
  • 퍼사드를 사용하는 사용자는 서브시스템을 구성하는 객체로 직접 접근하지 않아도 됨.

 

결과

  1. 서브시스템의 구성요소를 보호할 수 있음. 사용자가 다루어야 할 객체의 수가 줄어듬.
  2. 서브시스템과 사용자 코드 간의 결합도를 더욱 약하게 만듬. 서브시스템 내 정의된 요소들은 강하게 결합될 수 있음. 서브시스템의 사소한 변경으로 인한 재컴파일 시, 컴파일 의존성을 최소화할 수 있음.
  3. 응용프로그램 쪽에서 서브시스템 클래스를 사용하는 것을 완전히 막지는 않음. Facade를 사용할지 서브시스템 클래스를 직접 사용할지 결정할 수 있음.

 

구현 / 고려 사항

  1. 사용자와 서브시스템 간의 결합도 줄이기
    1. Facede를 추상 클래스로 정의. Facade의 서브클래스를 만들어 서브시스템에 대한 구체화.
    2. 사용자는 Facade만 사용하지 때문에 어떤 서브시스템의 구현이 사용되는지 알 필요 없음.
  2. 서브시스템 클래스 중 공개할 것과 감출 것
    1. 서브시스템도 클래스처럼 공개용 인터페이스가 있고 서브시스템 자체인 비공개 인터페이스가 있음. 무엇을 공개할 지 비공개로 할지 고민해봐야 함.
    2. 서브시스템 클래스를 비공개로 하는 것을 매우 유용하지만 많은 객체지향 언어가 이런 기능을 제공하지는 않음. 반대로 전체 공개는 클래스에 대한 네임 스페이스를 추가함으로써 가능함.

 

예제 코드

  • 좋은 밤을 만들어주는 GoodNightMaker를 만들고 그 안에 HaveAGoodNight 메서드를 만들겠습니다.
  • 인자로 받은 대상에 대해 좋은 밤을 보낼 수 있도록 갖가지 치료를 해주겠습니다. 이 때 HavaAGoodNight 메서드 내에서 좋은 밤을 보낼 수 있도록 여러 객체들이 도움을 줍니다.
#include "Facade1.h"
#include <iostream>

int main()
{
	Man man;
	GoodNightMaker goodnight_maker;
	
	std::cout << "남자의 행복도 : " << man.GetHappiness() << std::endl;

	goodnight_maker.HaveAGoodNight(&man, 8, Bed::Type::soft);

	std::cout << "남자의 행복도 : " << man.GetHappiness() << std::endl;

	return 0;
}

  • 남자가 잘자는 기능을 해주는 Facade 객체가 HavaAGoodNight 메서드를 통해 남자의 행복감을 올려줬습니다.
//Facade1.h

#pragma once

class Man
{
public:
	void AddHappiness(int happiness) { this->happiness += happiness; }
	int GetHappiness() { return happiness; }

private:
	int happiness = 0;
};

class Sleep
{
public:
	bool EnsureGoodNight(Man* man, int hours);
};

class GirlFriend
{
public:
	void GoodNightKiss(Man* man);
};

class Bed
{
public:
	enum class Type
	{
		hard,
		soft
	};

public:
	Bed(Type type) : type(type) {}

public:
	bool IsSoftBed() { return type == Type::soft; }

private:
	Type type;
};

class GoodNightMaker
{
public:
	void HaveAGoodNight(Man* man, int sleep_horus, Bed::Type bed_type);
};
  • 남자가 잘 잘 수 있게끔 도와주는 Sleep, GirlFriend, Bed 라고 했을 때 (이 3가지를 위에서 설명하던 서브시스템이라고 합시다.) 이 3가지를 한데 모아 GoodNightMaker 내의 HaveAGoodNight 메서드 내에서 남자에게 좋은 잠을 선사합니다.
//Facede1.cpp

#include "Facade1.h"
#include <iostream>

void GoodNightMaker::HaveAGoodNight(Man* man, int sleep_horus, Bed::Type bed_type)
{
	GirlFriend girl_friend;
	Sleep sleep;
	Bed bed(bed_type);

	girl_friend.GoodNightKiss(man);

	if (sleep.EnsureGoodNight(man, sleep_horus) == false)
	{
		std::cout << "충분한 잠을 자지 못했습니다." << std::endl;
	}

	if (bed.IsSoftBed())
	{
		man->AddHappiness(20.0f);
	}
}

bool Sleep::EnsureGoodNight(Man* man, int hours)
{
	if (hours >= 8)
	{
		man->AddHappiness(hours * 5.0f);
		return true;
	}
	else
	{
		return false;
	}
}

void GirlFriend::GoodNightKiss(Man* man)
{
	man->AddHappiness(30.0f);
}
  • HaveAGoodNight 메서드 내에서 GirlFriend, Sleep, Bed 객체(외부에서는 몰라도 되는 서브시스템)를 이용하여 남자에게 좋은 잠을 선사합니다.
    • 대신, 메서드 내에서 객체들이 강하게 결합되어 동작하는 모습을 볼 수 있습니다.
    • 반대로, main의 관점에선 서브시스템들과 약하게 결합될 수 있었습니다.

'디자인 패턴 > 구조' 카테고리의 다른 글

프록시(Proxy)  (0) 2024.01.02
플라이급(Flyweight)  (0) 2024.01.02
장식자(Decorator)  (0) 2023.12.22
복합체(Composite)  (2) 2023.12.21
가교(Bridge)  (2) 2023.12.21

+ Recent posts