정의
프로그램 실행 중 하나의 인스턴스만 존재하도록 보장하는 패턴.
전역 접근이 가능하며 보통 static 필드를 이용해 구현하지만, 핵심은 "전역에서 단 하나"라는 제약을 설계 의도로 담는 것.
예제 (C#)
public class GameManager
{
private static GameManager _instance;
public static GameManager Instance => _instance ??= new GameManager();
private GameManager() { }
public void InitGame() { /* 초기화 로직 */ }
}
정의
객체 생성을 전담하는 패턴. 생성 로직을 별도의 메서드나 클래스로 분리하여, 클라이언트가 구체적인 클래스 대신 인터페이스나 추상 클래스에 의존하게 만든다.
예제 (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("잘못된 타입")
};
}
정의
객체의 상태 변화를 감지하여, 이를 구독하고 있는 다른 객체들에게 자동으로 알리는 패턴.
예제 (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);
}
}
정의
서로 직접 참조하지 않는 객체들이 중재자를 통해 상호작용하는 패턴. 객체 간 결합도를 낮추고 상호작용을 한 곳에서 관리한다.
이벤트 버스(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}");
}
정의
객체가 가질 수 있는 상태를 객체화하고, 상태 변화에 따라 행동이 달라지도록 만드는 패턴. 상태 전이 규칙이 핵심.
예제 (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);
}
정의
요청을 객체로 캡슐화하여 호출, 취소, 재실행이 가능하게 하는 패턴. 명령 이력을 저장하여 나중에 되돌리거나 재실행할 수 있다.
예제 (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();
}
}
정의
알고리즘을 캡슐화하여 교체 가능하게 만드는 패턴. 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 | Strategy |
|---|---|---|
| 의도 | 상태 변화에 따라 행동이 달라짐 | 알고리즘(정책)을 실행 시점에 교체 |
| 전이 규칙 | 있음. 상태 객체나 컨텍스트가 전이를 결정 | 없음. 교체는 외부에서 결정 |
| 사용 예 | 플레이어 FSM, UI 라이프사이클 | 정렬 알고리즘, 데미지 계산 방식 |