발행-구독 패턴
발행자와 구독자, 그 사이에 중개인이 있는 패턴과 같다
발행자는 중개인에게 이벤트가 발생되었음을 알리고
중개인은 구독자에게 이벤트가 발생되었음을 알린다
발행자와 구독자가 서로를 모르지만,
중개인을 통해 이벤트의 발생과 소비가 이루어진다
발행-구독 패턴의 장단점
델리게이트를 통해 상호 의존성이 줄어든다
발행자는 중개인과의 통신만 연결되면 되고 구독자와는 연결을 하지 않는다
구독자도 중개인과의 통신만 연결되면 되고 발행자와는 연결을 하지 않는다
이는 한쪽에 문제가 생겨도 다른 쪽에 영향을 주지 않는 것을 의미하고
유지보수가 쉬워진다
하지만,
서로 반대 쪽의 상황을 알 수가 없기에
무슨 일이 발생되는지 자세히 파악할 수 없는 단점이 있다
언리얼에서의 발행-구독 패턴
언리얼에서는 델리게이트 기능을 통해 해당 패턴을 이용할 수 있다
델리게이트의 사전적 의미는 "대리자"이고 위에서 설명한 중개인과 같다
델리게이트는 발행자를 위한 Broadcast() 함수와
구독자를 위한 Add() 혹은 Bind() 함수를 제공한다
이벤트가 발생되면 발행자가 Broadcast() 함수를 호출하고,
그걸 구독(인지)하기 위해 Add() 혹은 Bind() 함수를 호출한다
언리얼 델리게이트 매크로 선언 방식
DECLARE_{델리게이트 유형}_DELEGATE_{바인드 될 함수}
- 델리게이트 유형
델리게이트 유형은 전달 방식과 프로그래밍 언어에 따라 결정된다
1:1, C++ | DECLARE_DELEGATE |
1:N, C++ | DECLARE_MULTICAST_DELEGATE |
1:1, C++ and Blueprint | DECLARE_DYNAMIC_DELEGATE |
1:N, C++ and Blueprint | DECALRE_DYNAMIC_MULTICAST_DELEGATE |
- 바인드 될 함수 명세
매개변수 없음, 반환값 없음 | 작성하지 않음 ex. DECLARE_DELEGATE |
매개변수 1개, 반환값 없음 | 마지막에 작성 ex. DECLARE_DELEGATE_OneParam |
매개변수 3개, 반환값 있음 (매개변수는 최대 9개까지 가능) |
마지막에 둘다 작성 ex. DECLARE_DELEGATE_RetVal_ThreeParams |
- 델리게이트 바인드 함수
Bind | 1:1 델리게이트 |
Add | 1:N 델리게이트 |
AddDynamic() | 1:N 다이나믹 델리게이트에 바인드 |
AddUObject() | 1:N 델리게이트에 멤버함수 바인드 |
AddUFunction() | 1:N 델리게이트에 UFUNCTION 멤버함수 바인드 |
언리얼 델리게이트 예제
1) 델리게이트 매크로 작성 및 선언
// SPigeon.h
...
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnPigeonFlying, const FString&, InName, const int32, InID);
/**
*
*/
UCLASS()
class STUDYPROJECT_API USPigeon
...
{
...
public:
FOnPigeonFlying OnPigeonFlying;
private:
...
};
2) 발행자의 Broadcast 작성
// SPigeon.cpp
...
void USPigeon::Fly()
{
...
OnPigeonFlying.Broadcast(*Name, ID);
}
...
3) 구독자의 바인드할 함수 작성
// SGameInstance.h
...
#include "SGameInstance.generated.h"
class USPigeon;
...
class STUDYPROJECT_API USGameInstance : public UGameInstance
{
...
public:
...
UFUNCTION()
void HandlePigeonFlying(const FString& InName, const int32 InID);
protected:
...
UPROPERTY()
TObjectPtr<USPigeon> SpawnedPigeon;
};
4) 발행자와 구독자 바인드
// SGameInstance.cpp
...
void USGameInstance::Init()
{
Super::Init();
SpawnedPigeon = NewObject<USPigeon>();
SpawnedPigeon->SetPigeonName(TEXT("SpawnedPigeon"));
SpawnedPigeon->SetPigeonID(7);
if (SpawnedPigeon->OnPigeonFlying.IsAlreadyBound(this, &ThisClass::HandlePigeonFlying) == false)
{
SpawnedPigeon->OnPigeonFlying.AddDynamic(this, &ThisClass::HandlePigeonFlying);
}
SpawnedPigeon->Fly();
}
void USGameInstance::Shutdown()
{
Super::Shutdown();
if (true == SpawnedPigeon->OnPigeonFlying.IsAlreadyBound(this, &ThisClass::HandlePigeonFlying))
{
SpawnedPigeon->OnPigeonFlying.RemoveDynamic(this, &ThisClass::HandlePigeonFlying);
}
}
void USGameInstance::HandlePigeonFlying(const FString& InName, const int32 InID)
{
UE_LOG(LogTemp, Log, TEXT("[%d] %s is now flying."), InID, *InName);
}
'게임 엔진 > [코드조선] 언리얼' 카테고리의 다른 글
언리얼 문자열 - FName, FText (0) | 2024.05.10 |
---|---|
언리얼 문자열 - TCHAR, FString (0) | 2024.05.10 |
언리얼 오브젝트 기능 - Serialization (0) | 2024.05.10 |
언리얼 오브젝트 기능 - Smart Pointer (0) | 2024.05.09 |
언리얼 오브젝트 기능 - C++ 로우 포인터 문제 해결 (0) | 2024.05.09 |