Decoupling

Ricon·2025년 3월 11일
0

기초 이론

목록 보기
6/6

Dependency Injection

  • 외부에서 객체를 생성하여 넘겨주는 것

예를 들어 A Class가 B Class를 의존할 때, B Object를 A가 직접 생성하지 않고 외부에서 생성해서 넘겨주면 의존성 주입했다고 한다.

  • 클래스 간의 강한 의존성을 제거하여 유연한 코드 구조 유지

왼쪽은 A에서 B를 생성하는 의존 형태, 오른쪽은 외부에서 B 객체를 생성하고 A에게 주입하는 형태

public interface IWeapon
{
    void Attack();
}

public class Sword : IWeapon
{
    public void Attack() => Debug.Log("검 공격!");
}

public class Player
{
    private IWeapon weapon;

    public Player(IWeapon weapon) // 의존성 주입
    {
        this.weapon = weapon;
    }

    public void Attack() => weapon.Attack();
}

// 사용 예시
Player player = new Player(new Sword()); // 무기를 자유롭게 변경 가능

Observer Pattern

  • 한 객체의 상태가 변경되면 자동으로 여러 객체에 알림을 보내는 패턴.
  • 객체 간 직접적인 참조 없이 이벤트 기반으로 결합도 최소화
public class EventManager
{
    public static event Action OnPlayerDeath;

    public static void PlayerDied() => OnPlayerDeath?.Invoke();
}

public class UIManager
{
    public UIManager() => EventManager.OnPlayerDeath += ShowGameOverScreen;

    private void ShowGameOverScreen() => Debug.Log("게임 오버!");
}

Event Bus(Pub-Sub)

  • 이벤트를 중앙에서 관리하는 방식으로, 각 객체가 직접 참조하지 않고 메시지를 통해 통신.
  • 메시지를 이용한 통신으로 모듈 간 강한 결합을 제거
public class EventBus
{
    private static Dictionary<Type, Action<object>> events = new Dictionary<Type, Action<object>>();

    public static void Subscribe<T>(Action<T> listener)
    {
        if (!events.ContainsKey(typeof(T))) events[typeof(T)] = obj => { };
        events[typeof(T)] += obj => listener((T)obj);
    }

    public static void Publish<T>(T message)
    {
        if (events.ContainsKey(typeof(T))) events[typeof(T)](message);
    }
}

// 사용 예시
public class Enemy
{
    public void TakeDamage(int damage) => EventBus.Publish(new DamageEvent(damage));
}

public class UIManager
{
    public UIManager() => EventBus.Subscribe<DamageEvent>(OnDamageReceived);

    private void OnDamageReceived(DamageEvent e) => Debug.Log($"체력 감소: {e.damage}");
}

Service Locator

  • 서비스(의존성 객체)를 글로벌 레지스트리를 통해 조회하는 방식
  • 객체 간 직접적인 참조 없이 중앙에서 관리 가능
public class ServiceLocator
{
    private static Dictionary<Type, object> services = new Dictionary<Type, object>();

    public static void Register<T>(T service) => services[typeof(T)] = service;
    public static T Get<T>() => (T)services[typeof(T)];
}

// 사용 예시
ServiceLocator.Register<IWeapon>(new Sword());
IWeapon weapon = ServiceLocator.Get<IWeapon>();
weapon.Attack();

Command Pattern

  • 명령을 하나의 객체로 캡슐화하여 실행하는 방식.
  • 실행할 동작을 객체로 관리하여 유연한 동작 가능
public interface ICommand
{
    void Execute();
}

public class JumpCommand : ICommand
{
    public void Execute() => Debug.Log("점프 실행!");
}

public class InputHandler
{
    private ICommand command;

    public void SetCommand(ICommand command) => this.command = command;
    public void ExecuteCommand() => command?.Execute();
}

// 사용 예시
InputHandler inputHandler = new InputHandler();
inputHandler.SetCommand(new JumpCommand());
inputHandler.ExecuteCommand();

Strategy Pattern

  • 행동(알고리즘)을 객체로 분리하여 교체 가능하게 만듦
  • 특정 행동을 동적으로 변경할 수 있음
public interface IAttackStrategy
{
    void Attack();
}

public class SwordAttack : IAttackStrategy
{
    public void Attack() => Debug.Log("검 공격!");
}

public class Player
{
    private IAttackStrategy attackStrategy;

    public void SetStrategy(IAttackStrategy strategy) => attackStrategy = strategy;
    public void Attack() => attackStrategy?.Attack();
}

// 사용 예시
Player player = new Player();
player.SetStrategy(new SwordAttack());
player.Attack();

State Pattern

  • 객체의 상태를 독립적으로 관리하여 상태 변경을 쉽게 만듦
  • 상태 변경이 용이하며, 상태 로직을 분리 가능
public interface IState
{
    void Handle();
}

public class IdleState : IState
{
    public void Handle() => Debug.Log("대기 상태");
}

public class Player
{
    private IState state;

    public void SetState(IState newState) => state = newState;
    public void Update() => state?.Handle();
}

// 사용 예시
Player player = new Player();
player.SetState(new IdleState());
player.Update();

0개의 댓글