디자인 패턴 정리: 옵저버 패턴, 이벤트 버스 패턴, 명령 패턴

ggm-_-·4일 전
0

TIL (Tody I Learn)

목록 보기
53/53

2025.02.16(일)
스탠다드 반에서 진행한 디자인 패턴 2번째 강의를 정리합니다.

Unity 6기 스탠다드 반에서 송지원 튜터님이 강의하신 디자인 패턴 강의를 바탕으로 작성한 글입니다.

이전 글: 디자인 패턴 정리: 싱글톤 패턴, 오브젝틑 풀 패턴, 전략 패턴, 상태 패턴

이 글에서 다룰 패턴들

  • 옵저버 패턴
  • 이벤트 버스 패턴
  • 명령 패턴

이벤트 기반 프로그래밍

  • 이벤트 기반 프로그래밍은 효율적으로 프로그램이 실행되도록 설계할 수 있다.
  • 이를 통해 코드 실행의 흐름을 효율화할 수 있다.
  • Pub-Sub 패턴이라고도 할 수 있다.
    (publish발행 subscribe구독 패턴)
발행자구독자대응 방식
11함수 호출
1can be N옵저버 패턴
can be Ncan be N이벤트 버스 패턴

옵저버 패턴

1 발행자, N 구독자인 Pub-Sub 패턴

  • 옵저버 패턴은 구독자들이 발행자를 관찰하며 발행자가 이벤트를 발생시켰을 때 반응한다.
  • 옵저버 패턴을 구현하고 있지 않으면 매 프레임마다 발행자를 관찰해야된다.

이벤트 버스 패턴

N 발행자, N 구독자인 Pub-Sub 패턴

왜 쓸까?

  • 이벤트 구현 시 발행자와 구독자 사이에서 의존성을 만들지 않고 싶어서
  • 퀘스트 시스템을 구현할 때 퀘스트의 종류가 많지 않아, 간단하고 이해가 슉슉되는 이벤트 시스템을 만들고 싶을 수 있다.
  • 그리고 이벤트의 발행자와 구독자 간의 의존성을 만들지 않은 상태에서요.

구현

  • EventBus에는 액션을 등록하고, Publisher가 이벤트를 Invoke하도록 한다.
    이때, Publisher가 한 개의 클래스라는 가정은 없고, 모두가 공용으로 쓰는 EventManager가 탄생한다.

이벤트 버스 패턴 고려사항

  • 이벤트 버스에 대한 의존성이 너무 높아질 가능성이 있다.
  • 복잡해질 경우 이벤트 관리가 안될 가능성이 있다. (<- 근데 튜터님은 써보니까 너무 편했다고 한다)

명령 패턴

행동을 객체화해서 복잡한 작업을 순차적으로 처리하거나 되돌릴 수 있게 만드는 패턴

왜 쓸까?

  • 행동을 객체로 만들어 재사용, 기록, 취소, 병렬 처리를 쉽게 하기 위해

❓ 왜 명령을 객체로 묶을까?

할 일들을 To-Do리스트로 만든다고 생각해보자. 이때, 우리는 자연스럽게 할 일들을 객체화할 생각을 하게 된다. 언제? 무엇을? 어디에서? 누구랑? 언제까지?와 같은 내용들을 묶으려고 하다보면, 행동과 관련된 정보를 객체로 묶고 이를 체계적으로 관리하는 것은 매우 좋은 해결책이 될 것이다.

구현

명령 패턴의 주요 구성 요소는 다음과 같다.

1. Command (명령 인터페이스)

  • 실행될 명령을 정의하는 인터페이스 또는 추상 클래스
    Execute(), Undo() 등의 메서드를 보유

2. ConcreteCommand (구체적인 명령 클래스)

  • Command 인터페이스를 구현하여 특정 동작을 수행
    명령을 실행할 실제 객체(Receiver)를 참조하여 요청을 전달

3. Receiver (실제 동작을 수행하는 객체)

  • ConcreteCommand가 실행할 기능을 가진 객체

4. Invoker (명령을 요청하는 객체)

  • Command 객체를 보관하고 있다가 특정 시점에 실행

5. Client (클라이언트)

  • ConcreteCommand를 생성하고 Invoker에 전달

구현 예제 코드

  • 예제 코드
// 1. Command 인터페이스 정의
public interface ICommand
{
    void Execute();
    void Undo();
}

// 2. Receiver (명령을 실행하는 실제 객체)
public class Player
{
    public void Jump()
    {
        Debug.Log("Player Jumped!");
    }

    public void UndoJump()
    {
        Debug.Log("Jump Undone!");
    }
}

// 3. ConcreteCommand (구체적인 명령)
public class JumpCommand : ICommand
{
    private Player _player;

    public JumpCommand(Player player)
    {
        _player = player;
    }

    public void Execute()
    {
        _player.Jump();
    }

    public void Undo()
    {
        _player.UndoJump();
    }
}

// 4. Invoker (명령을 저장하고 실행)
public class CommandInvoker
{
    private ICommand _command;

    public void SetCommand(ICommand command)
    {
        _command = command;
    }

    public void ExecuteCommand()
    {
        _command?.Execute();
    }

    public void UndoCommand()
    {
        _command?.Undo();
    }
}

// 5. Client (사용 예)
public class GameManager : MonoBehaviour
{
    private CommandInvoker _invoker = new CommandInvoker();
    private Player _player = new Player();

    void Start()
    {
        ICommand jumpCommand = new JumpCommand(_player);
        _invoker.SetCommand(jumpCommand);

        // 버튼 클릭 시 실행
        _invoker.ExecuteCommand(); // "Player Jumped!" 출력
        _invoker.UndoCommand();    // "Jump Undone!" 출력
    }
}

다음에 공부할 패턴

  • 메멘토 패턴
  • 파사드 패턴
  • etc...
profile
미숙한 초보 게임 개발자

0개의 댓글

관련 채용 정보