(25/08/12)디자인 패턴 정리

허윤·2025년 8월 12일

디자인 패턴 정리

목차

  1. Singleton
  2. Factory
  3. Observer
  4. Mediator
  5. State
  6. Command
  7. Strategy
  8. State vs Strategy 차이

디자인 패턴 정리

Singleton

정의
프로그램 실행 중 하나의 인스턴스만 존재하도록 보장하는 패턴.
전역 접근이 가능하며 보통 static 필드를 이용해 구현하지만, 핵심은 "전역에서 단 하나"라는 제약을 설계 의도로 담는 것.

예제 (C#)

public class GameManager
{
    private static GameManager _instance;
    public static GameManager Instance => _instance ??= new GameManager();

    private GameManager() { }

    public void InitGame() { /* 초기화 로직 */ }
}

Factory

정의
객체 생성을 전담하는 패턴. 생성 로직을 별도의 메서드나 클래스로 분리하여, 클라이언트가 구체적인 클래스 대신 인터페이스나 추상 클래스에 의존하게 만든다.

예제 (C#)

public interface IWeapon { void Attack(); }

public class Sword : IWeapon { public void Attack() => Console.WriteLine("검 휘두르기"); }
public class Bow : IWeapon { public void Attack() => Console.WriteLine("화살 쏘기"); }

public static class WeaponFactory
{
    public static IWeapon Create(string type) =>
        type switch
        {
            "Sword" => new Sword(),
            "Bow" => new Bow(),
            _ => throw new ArgumentException("잘못된 타입")
        };
}

Observer

정의
객체의 상태 변화를 감지하여, 이를 구독하고 있는 다른 객체들에게 자동으로 알리는 패턴.

예제 (C#)

public interface IObserver { void Update(int hp); }

public class HPBar : IObserver
{
    public void Update(int hp) => Console.WriteLine($"HP 바 업데이트: {hp}");
}

public class Player
{
    private List<IObserver> observers = new();
    private int hp;
    public void Attach(IObserver observer) => observers.Add(observer);
    public void SetHP(int value)
    {
        hp = value;
        foreach (var obs in observers) obs.Update(hp);
    }
}

Mediator

정의
서로 직접 참조하지 않는 객체들이 중재자를 통해 상호작용하는 패턴. 객체 간 결합도를 낮추고 상호작용을 한 곳에서 관리한다.
이벤트 버스(Event Aggregator)와 유사하지만, Mediator는 로직을 직접 중재하고 오케스트레이션한다.

예제 (C#)

public interface IMediator
{
    void Send(string message, Colleague sender);
}

public abstract class Colleague
{
    protected IMediator mediator;
    public Colleague(IMediator m) => mediator = m;
}

public class ConcreteMediator : IMediator
{
    public ColleagueA A { get; set; }
    public ColleagueB B { get; set; }

    public void Send(string message, Colleague sender)
    {
        if (sender == A) B.Receive(message);
        else A.Receive(message);
    }
}

public class ColleagueA : Colleague
{
    public ColleagueA(IMediator m) : base(m) { }
    public void Send(string msg) => mediator.Send(msg, this);
    public void Receive(string msg) => Console.WriteLine($"A가 받은 메시지: {msg}");
}

public class ColleagueB : Colleague
{
    public ColleagueB(IMediator m) : base(m) { }
    public void Send(string msg) => mediator.Send(msg, this);
    public void Receive(string msg) => Console.WriteLine($"B가 받은 메시지: {msg}");
}

State

정의
객체가 가질 수 있는 상태를 객체화하고, 상태 변화에 따라 행동이 달라지도록 만드는 패턴. 상태 전이 규칙이 핵심.

예제 (C#)

public interface IState
{
    void Enter(Player p);
    void Update(Player p);
}

public class Idle : IState
{
    public void Enter(Player p) { Console.WriteLine("Idle 상태"); }
    public void Update(Player p)
    {
        if (p.Input.Move) p.ChangeState(new Run());
    }
}

public class Run : IState
{
    public void Enter(Player p) { Console.WriteLine("Run 상태"); }
    public void Update(Player p)
    {
        if (!p.Input.Move) p.ChangeState(new Idle());
    }
}

public class Player
{
    public (bool Move, bool Attack) Input;
    private IState _state = new Idle();

    public void ChangeState(IState state)
    {
        _state = state;
        _state.Enter(this);
    }

    public void Tick() => _state.Update(this);
}

Command

정의
요청을 객체로 캡슐화하여 호출, 취소, 재실행이 가능하게 하는 패턴. 명령 이력을 저장하여 나중에 되돌리거나 재실행할 수 있다.

예제 (C#)

public interface ICommand
{
    void Execute();
    void Undo();
}

public class AddHP : ICommand
{
    private Player player;
    private int amount;

    public AddHP(Player p, int a) { player = p; amount = a; }
    public void Execute() => player.HP += amount;
    public void Undo() => player.HP -= amount;
}

public class Invoker
{
    private Stack<ICommand> history = new();
    public void ExecuteCommand(ICommand cmd)
    {
        cmd.Execute();
        history.Push(cmd);
    }
    public void Undo()
    {
        if (history.Count > 0) history.Pop().Undo();
    }
}

Strategy

정의
알고리즘을 캡슐화하여 교체 가능하게 만드는 패턴. State 패턴과 달리 내부 전이 규칙 없이, 실행 시점에 전략을 선택해 적용한다.

예제 (C#)

public interface IDamageStrategy
{
    int Calculate(int atk, int def);
}

public class NormalDamage : IDamageStrategy
{
    public int Calculate(int atk, int def) => Math.Max(0, atk - def);
}

public class CriticalDamage : IDamageStrategy
{
    public int Calculate(int atk, int def) => Math.Max(0, (int)(atk * 1.5) - def);
}

public class Combat
{
    private IDamageStrategy strategy;
    public Combat(IDamageStrategy s) => strategy = s;
    public void SetStrategy(IDamageStrategy s) => strategy = s;
    public int DealDamage(int atk, int def) => strategy.Calculate(atk, def);
}

State vs Strategy 차이

구분StateStrategy
의도상태 변화에 따라 행동이 달라짐알고리즘(정책)을 실행 시점에 교체
전이 규칙있음. 상태 객체나 컨텍스트가 전이를 결정없음. 교체는 외부에서 결정
사용 예플레이어 FSM, UI 라이프사이클정렬 알고리즘, 데미지 계산 방식
profile
C# 클라이언트 프로그래밍 지망

0개의 댓글