퍼사드 패턴

서브시스템에 있는 일련의 인터페이스를 통합 인터페이스로 묶어준다.

고수준 인터페이스도 정의하므로 서브시스템을 더 편리하게 사용할 수 있다.

 

큰 인터페이스와 여러 인터페이스를 단순하게 바꾸거나 통합해야 할 때 쓰인다.

서브 시스템으로 퍼사드를 만들고 진짜 작업은 서브클래스에 맡긴다.

(클라이언트의 친구는 Facade 하나뿐)

 

최소 지식 원칙 (Principle of Knowledge)

객체 사이의 상호작용은 될 수 있으면 아주 가까운 '친구' 사이에서만 허용하는 편이 좋다.

 

친구를 만들지 않고 다른 객체에 영향력 행사하기

  • 객체 자체
  • 메소드에 매개변수로 전달된 객체
  • 메소르듣 생성하거나 인스턴스를 만든 객체
  • 객체에 속하는 구성요소
class Car {
private:
    Engine* engine;
public:
    void start(Key *key) {
    	Doors* doors = new Doors{};
    	bool authorized = key->turns(); // 메소드에 매개변수로 전달된 객체
        
        if (authorized) {
            engine->start(); // 객체에 속하는 구성 요소
            updateDashboardDisplay(); // 객체 자체 (객체 내에 있는 메소드)
            doores->lock();  // 메소드를 생성하거나 인스턴스를 만든 객체 (직접 만든 경우)
        }
    }
    
    void updateDashboardDisplay() {
    
    }
};

 

메소드를 호출한 결과로 리턴받은 객체에 들어있는 메소드를 호출할 때의 단점

-> 다른 객체의 일부분에 요청하게 되고, 직접적으로 알고 지내는 객체의 수가 증가

 

최소 지식 원칙을 따르려면 객체가 대신 요청하도록 만들어야 한다.

이러면 객체의 한 구성 요소를 알고 지낼 필요가 없고, 친구의 수를 줄이는 데도 도움이 된다.

// 원칙을 따르지 않은 경우
float getTemp() {
	Thermometer thermometer = station.getThermometer();
    return thermometer.getTemperature();
}
// station 으로부터 thermometer 객체를 받은 다음,
// 그 객체의 getTemperature() 메서드를 직접 호출



// 원칙을 따르는 경우
float getTemp() {
	return station.getTemperature();
}
// 최소 지식 원칙을 적용해어 thermometer 에게
// 요청을 전달하는 메소르듣 station 클래스에 추가
// 이러면 의존해야하는 클래스의 개수를 줄일 수 있다.

 

 

 

예제)

#include <iostream>

using namespace std;

class GameInstance {
public:
    // Get a Subsystem of specified type
    UGameInstanceSubsystem* GetSubsystemBase(TSubclassOf<UGameInstanceSubsystem> SubsystemClass) const
    {
        return SubsystemCollection.GetSubsystem<UGameInstanceSubsystem>(SubsystemClass);
    }

    // Get a Subsystem of specified type
    template <typename TSubsystemClass>
    TSubsystemClass* GetSubsystem() const
    {
        return SubsystemCollection.GetSubsystem<TSubsystemClass>(TSubsystemClass::StaticClass());
    }

    // 제공된 GameInstance에서 지정된 유형의 하위 시스템 가져오기
    // 하위 시스템을 찾을 수 없거나 GameInstance가 null인 경우 nullptr을 반환합니다.
    template <typename TSubsystemClass>
    static FORCEINLINE TSubsystemClass* GetSubsystem(const UGameInstance* GameInstance)
    {
        if (GameInstance)
        {
            return GameInstance->GetSubsystem<TSubsystemClass>();
        }
        return nullptr;
    }

    // 수명이 UGameInstance의 수명보다 짧다는 확신이 없으면 이 배열 참조를 유지하지 마십시오.
    template <typename TSubsystemClass>
    const TArray<TSubsystemClass*>& GetSubsystemArray() const
    {
        return SubsystemCollection.GetSubsystemArray<TSubsystemClass>(TSubsystemClass::StaticClass());
    }

private:
    FObjectSubsystemCollection<UGameInstanceSubsystem> SubsystemCollection;
};


class UISubsystem : public UGameInstanceSubsystem {
public:
    void ShowBaseUILayout();
    void HideBaseUILayout();
};

class SequenceSubsystem : public UGameInstanceSubsystem {
public:
    void SequencePlay(ALevelSequenceActor* sequenceActor) {
        sequenceActor->Play();
    }

    void SequenceStop(ALevelSequenceActor* sequenceActor) {
        sequenceActor->Stop();
    }
};


int main () {

    // 최소 지식 원칙 적용하여 사용
    GetGameInstance()->GetSubsystem<UISubsystem>()->ShowBaseUILayout();
    GetGameInstance()->GetSubsystem<UISubsystem>()->HideBaseUILayout();

    // 실제 언리얼 에서는 GetSubsystem 비용이 비싸 변수에 저장한 다음 사용
    TObjectPtr<UISubsystem> uiSubsystem = GetGameInstance()-><UISubsystem>();
    uiSubsystem->ShowBaseUILayout();
    uiSubsystem->HideBaseUILayout();
}

 

+ Recent posts