개념공부

디자인 패턴 : 중재자 패턴

Cadi 2025. 1. 8. 23:40

중재자 패턴

  • 다대 다 (N : N)의 관계에서 객체 간의 직접 통신을 막고, 모든 통신을 중재자를 통해서 해결
  • 객체들 간의 상호작용은 직접적으로 연결되지 않음
  • 객체는 오직 중재자만 참조함

예를 들자면, 카카오톡을 생각하면 된다. 다른 사람 1,2,3 에게 메세지를 보내고 싶다면 하나하나씩 보내는 것보다

중재자(카카오톡 그룹방)에 올리면 사람들이 그걸 보는 방식이라고 이해하면 편하다. 

 

옵저버 패턴과의 다른 점은 다음과 같다. 

 

 

옵저버 패턴의 예시를 먼저 보자

// Subject 인터페이스
public interface ISubject
{
    void RegisterObserver(IObserver observer);
    void UnregisterObserver(IObserver observer);
    void NotifyObservers();
}

// Observer 인터페이스
public interface IObserver
{
    void OnNotify(); // 주체로부터 알림을 받을 메서드
}

// Subject 구현 (버튼)
public class ButtonSubject : MonoBehaviour, ISubject
{
    private List<IObserver> observers = new List<IObserver>();

    public void RegisterObserver(IObserver observer)
    {
        observers.Add(observer);
    }

    public void UnregisterObserver(IObserver observer)
    {
        observers.Remove(observer);
    }

    public void NotifyObservers()
    {
        foreach (var observer in observers)
        {
            observer.OnNotify(); // 모든 옵저버들에게 알림
        }
    }

    public void OnButtonClick() // 버튼 클릭 시 호출
    {
        NotifyObservers(); // 상태 변화 알림
    }
}

// Observer 구현 (텍스트 업데이트)
public class TextObserver : MonoBehaviour, IObserver
{
    public void OnNotify()
    {
        Debug.Log("텍스트가 업데이트되었습니다.");
    }
}

// Observer 구현 (이미지 변경)
public class ImageObserver : MonoBehaviour, IObserver
{
    public void OnNotify()
    {
        Debug.Log("이미지가 변경되었습니다.");
    }
}

 

옵저버를 등록해두면, 모든 옵저버들에게 돌아가면서 OnNotify함수를 호출해 ! 라고 알린다.

주체에서 상태 변화를 알리면, 옵저버들이 자신의 행동을 수행하는 구조, 하지만 동시에 여러 옵저버가 동일한 알람을 받으며, 각 옵저버가 각기 다른 이벤트를 처리하기 어렵다. 

 

반면, 중재자 패턴은 약간 다르다고 할 수 있다. 

// 1. 중재자 인터페이스
public interface IMediator
{
    void Notify(object sender, string eventType);
}

// 2. 이벤트 인터페이스들
public interface IButtonEventHandler
{
    void HandleButtonEvent();
}

public interface ICollisionEventHandler
{
    void HandleCollisionEvent();
}

// 3. 구체 중재자
public class GameMediator : MonoBehaviour, IMediator
{
    public ButtonHandler buttonHandler; // 버튼
    public CollisionHandler collisionHandler; // 충돌
    public UIHandler uiHandler; // UI

    public void Notify(object sender, string eventType)
    {
        if (eventType == "ButtonClick")
        {
            buttonHandler.HandleButtonEvent(); // 버튼 이벤트 전달
        }
        else if (eventType == "Collision")
        {
            collisionHandler.HandleCollisionEvent(); // 충돌 이벤트 전달
        }
        else if (eventType == "UIChange")
        {
            uiHandler.UpdateUI(); // UI 변경 이벤트 전달
        }
    }
}

// 4. 버튼 이벤트 핸들러
public class ButtonHandler : MonoBehaviour, IButtonEventHandler
{
    public void HandleButtonEvent()
    {
        Debug.Log("버튼 클릭 이벤트 처리 중...");
    }
}

// 5. 충돌 이벤트 핸들러
public class CollisionHandler : MonoBehaviour, ICollisionEventHandler
{
    public void HandleCollisionEvent()
    {
        Debug.Log("충돌 이벤트 처리 중...");
    }
}

// 6. UI 변경 핸들러
public class UIHandler : MonoBehaviour
{
    public void UpdateUI()
    {
        Debug.Log("UI 변경 이벤트 처리 중...");
    }
}

// 7. 이벤트 발생
public class Player : MonoBehaviour
{
    public GameMediator mediator;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.B))
        {
            mediator.Notify(this, "ButtonClick"); // 버튼 클릭 이벤트 발생
        }

        if (Input.GetKeyDown(KeyCode.C))
        {
            mediator.Notify(this, "Collision"); // 충돌 이벤트 발생
        }

        if (Input.GetKeyDown(KeyCode.U))
        {
            mediator.Notify(this, "UIChange"); // UI 변경 이벤트 발생
        }
    }
}

 

지금은 각각의 핸들러마다 요소가 한 가지씩 있지만, 각각의 인터페이스를 리스트로 만들어서

반복문을 돌려서 모두 처리하면 된다.

 

 

즉, 중재자는 이벤트를 구분하여 특정 구독자에게만 전달한다.

 

// 1. 중재자 인터페이스
public interface IMediator
{
    void Notify(object sender, string eventType);
}

// 2. 구독자 인터페이스
public interface IEventHandler
{
    void HandleEvent(string eventType);
}

// 3. 구체 중재자: 여러 핸들러를 관리
public class GameMediator : MonoBehaviour, IMediator
{
    private Dictionary<string, List<IEventHandler>> handlers = new Dictionary<string, List<IEventHandler>>();

    // 특정 이벤트에 핸들러 등록
    public void RegisterHandler(string eventType, IEventHandler handler)
    {
        if (!handlers.ContainsKey(eventType))
        {
            handlers[eventType] = new List<IEventHandler>();
        }
        handlers[eventType].Add(handler);
    }

    // 알림 전송
    public void Notify(object sender, string eventType)
    {
        if (handlers.ContainsKey(eventType))
        {
            foreach (var handler in handlers[eventType])
            {
                handler.HandleEvent(eventType); // 핸들러 호출
            }
        }
    }
}

// 4. 버튼 핸들러
public class ButtonHandler : MonoBehaviour, IEventHandler
{
    public void HandleEvent(string eventType)
    {
        if (eventType == "ButtonClick")
        {
            Debug.Log("버튼 클릭 이벤트 처리 중...");
        }
    }
}

// 5. 충돌 핸들러
public class CollisionHandler : MonoBehaviour, IEventHandler
{
    public void HandleEvent(string eventType)
    {
        if (eventType == "Collision")
        {
            Debug.Log("충돌 이벤트 처리 중...");
        }
    }
}

// 6. UI 핸들러
public class UIHandler : MonoBehaviour, IEventHandler
{
    public void HandleEvent(string eventType)
    {
        if (eventType == "UIChange")
        {
            Debug.Log("UI 변경 이벤트 처리 중...");
        }
    }
}

// 7. 이벤트 발생
public class Player : MonoBehaviour
{
    public GameMediator mediator;

    void Start()
    {
        // 핸들러 등록
        mediator.RegisterHandler("ButtonClick", new ButtonHandler());
        mediator.RegisterHandler("Collision", new CollisionHandler());
        mediator.RegisterHandler("UIChange", new UIHandler());
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.B))
        {
            mediator.Notify(this, "ButtonClick"); // 버튼 클릭 이벤트 발생
        }

        if (Input.GetKeyDown(KeyCode.C))
        {
            mediator.Notify(this, "Collision"); // 충돌 이벤트 발생
        }

        if (Input.GetKeyDown(KeyCode.U))
        {
            mediator.Notify(this, "UIChange"); // UI 변경 이벤트 발생
        }
    }
}

 

 

아직 정확히 이해하지 못해서, 써 보면서 이해해야겠다.