Showing

[디자인 패턴] 옵저버 패턴 crowd 군중 시뮬레이션 본문

Design Pattern

[디자인 패턴] 옵저버 패턴 crowd 군중 시뮬레이션

RabbitCode 2023. 12. 12. 16:42

 

옵저버 패턴은 객체 간의 일대다 의존성을 정의하는 디자인 패턴으로,

 

하나의 객체를 중심으로 다른 객체들이 반응해야할 경우에 매우 유용하므로 군중 시뮬레이션에 적절하게 쓰일 수 있다.

 

무대 위의 배우와 그것을 바라보는 관객의 비유가 알맞은 패턴이다.

관객은 서로서로의 정보를 알지 못해도 상관없다.

다만 배우는 어떤 관객들에게 연기를 펼치는지만 알고 있다.

클래스 간의 의존성 줄이고 자 함-> ‘디 커플링’ -> 리스크 헷지

 

그러므로 옵저버 패턴 구현의 핵심은,

1) 배우는 관객들을 알고 있다.

따라서 배우가 될 클래스에서 옵저버 인터페이스의 배열을 들고 있다.

2) 관객들은 옵저버가 되어야 하므로 옵저버 인터페이스를 상속받고, 인터페이스 정의부에 있는 함수를 구현하면서 어떤 행위를 할지 결정한다.

3) 배우가 특정 행위를 할 때 옵저버들에게 Notift한다.

 

파이썬으로 작성하는 옵저버 패턴의 원형은 아래와 같다.

옵저버인터페이스란 클래스를 만들어준다.

#pragma once

#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "ObserverInterface.generated.h"

// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UObserverInterface : public UInterface
{
	GENERATED_BODY()
};

/**
 * 
 */
class THIRDPERSONTEMPLATE_API IObserverInterface
{
	GENERATED_BODY()

	// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
};
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "ObserverInterface.generated.h"

// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UObserverInterface : public UInterface
{
	GENERATED_BODY()
};

/**
 * 
 */
class THIRDPERSONTEMPLATE_API IObserverInterface
{
	GENERATED_BODY()

	// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
	// 옵저버에게 공격 알림을 전달하는 함수
	virtual void NotifyAttack() = 0;
};

 

배우 역할을 해줄 Enemy에 옵저버 패턴을 적용해준다.

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Unit.h"
#include "ObserverInterface.h"
#include "Enemy.generated.h"

/**
 * 
 */
UCLASS()
class THIRDPERSONTEMPLATE_API AEnemy : public AUnit, public IObserverInterface
{
	GENERATED_BODY()
public:
	AEnemy();
	// 유닛 클래스의 추상 함수를 오버라이드하여 구현
	virtual void Attack_Implementation() override;
	virtual void Defend_Implementation() override;

	//IObserverInterface 인터페이스의 가상 함수를 구현
	virtual void NotifyAttack() override;

	//옵저버 등록 및 알림 전달 함수
	void RegisterObserver(IObserverInterface* Observer);
	void UnRegisterObserver(IObserverInterface* Observer);
private:
	TArray<IObserverInterface*> Observers;
};

 

// Fill out your copyright notice in the Description page of Project Settings.


#include "Enemy.h"

AEnemy::AEnemy()
{
}

void AEnemy::Attack_Implementation() // 클래스 구현인 액터가 공격했다
{
	// 적의 공격 기능 구현
	UE_LOG(LogTemp, Warning, TEXT("Enemy is Attacking!"));
	// 공격 능력을 사용하면 옵저버에게 알림을 보낸다.
	// 다른 예시로 무대 위의 배우가 죽으면 관객(군중)들이 눈물을 흘리는 경우
	for (IObserverInterface* Ob : Observers) {
		if (Ob) {
			Ob->NotifyAttack(); // 옵저버들에게 공격을 알린다
		}
	}

}

void AEnemy::Defend_Implementation()
{
	UE_LOG(LogTemp, Warning, TEXT("Enemy is Defending!"));
}

void AEnemy::NotifyAttack()
{
}

void AEnemy::RegisterObserver(IObserverInterface* Observer)
{
	Observers.AddUnique(Observer);
}

void AEnemy::UnRegisterObserver(IObserverInterface* Observer)
{
	Observers.Remove(Observer);
}