[Design pattern] 중재자 패턴 (Mediator pattern)


Study/Design Pattern  2019. 6. 10. 23:57

안녕하세요. 명월입니다.


이 글은 중재자 패턴에 대한 설명입니다.


중재자 패턴은 사실 크게 복잡한 건 아닙니다. 그러나 이 패턴에 대한 내용을 확인하기 위해 다른 위키나 블로그 등을 보면 좀 어렵게 설명되어 있습니다. 그래서 예전에 공부할 때 좀 어려웠다라고 생각했던거 같습니다.

그래서 저는 그냥 클래스 간에 상위, 하위 개념 없이 순환 참조 에러와 같지 않을까 생각됩니다. 사실 그렇게 생각하는게 편합니다.

// 이건 중재자 패턴이 아닌 나쁜 프로그램 디자인의 예.
class Controller
{
  // Action 클래스를 명시한다.
  public void Run(Action action)
  {
    action.Draw(this);
  }
  public void OnConnected()
  {
    Console.WriteLine("Connection!!");
  }
}
class Action
{
  // Controller 클래스를 명시한다.
  public void Draw(Controller controller)
  {
    controller.OnConnected();
  }
}
class Program
{
  static void Main(string[] args)
  {
    var controller = new Controller();
    var action = new Action();
    controller.Run(action);
    Console.WriteLine("Press any key...");
    Console.ReadKey();
  }
}

위 소스는 중재자 패턴의 예제가 아닙니다. 그냥 Controller 클래스와 Action 클래스가 서로 참조하는 형태입니다. 즉, Controller의 Run 함수에서 action Draw를 호출하고 다시 action Draw함수에서 OnConnected함수를 호출합니다.

솔직히 이렇게 작성하면 클래스를 두 개로 나눈 의미 조차 없어 보입니다. 이렇게 될 경우, 서로 간의 결합도가 너무 높아서 복잡한 프로그램의 경우는 Controller를 수정할 때마다 Action클래스도 그에 맞게 수정해야 하는 경우가 발생합니다.

interface IMediator
{
  void AddAction(IAction action);
  void AddController(IController controller);
  void Connect();
  void Draw();
}
interface IController
{
  void Run();
  void OnConnected();
}
interface IAction
{
  void Draw();
}
// 중재자 클래스 안에 Controller 클래스와 Action 클래스를 받을 수 있게 한다.
class Mediator : IMediator
{
  private IAction action = null;
  private IController controller = null;
  public void AddAction(IAction action)
  {
    this.action = action;
  }
  public void AddController(IController controller)
  {
    this.controller = controller;
  }
  public void Connect()
  {
    this.controller.OnConnected();
  }
  public void Draw()
  {
    this.action.Draw();
  }
}
class Controller : IController
{
  private IMediator mediator;
  public Controller(IMediator mediator)
  {
    // 중재자 클래스에 설정
    this.mediator = mediator;
    this.mediator.AddController(this);
  }
  public void Run()
  {
    // Run을 부르면 중재자 클래스의 Draw 함수 호출
    this.mediator.Draw();
  }
  public void OnConnected()
  {
    Console.WriteLine("Connection!!");
  }
}
class Action : IAction
{
  private IMediator mediator;
  public Action(IMediator mediator)
  {
    // 중재자 클래스에 설정
    this.mediator = mediator;
    this.mediator.AddAction(this);
  }
  public void Draw()
  {
    // Draw를 부르면 중재자 클래스의 Connect 함수 호출
    mediator.Connect();
  }
}
class Program
{
  static void Main(string[] args)
  {
    var mediator = new Mediator();
    var controller = new Controller(mediator);
    var action = new Action(mediator);
    controller.Run();
    Console.WriteLine("Press any key...");
    Console.ReadKey();
  }
}

위 소스처럼 Controller 클래스와 Action 클래스가 서로 직접 참조가 아닌 중재자 클래스를 작성해서 중재자 클래스를 이용하여 서로 참조하게 하였습니다. 이렇게 하면, 나중에 Action을 수정할 경우는 중재자 클래스와 Action 클래스만 수정하고 Controller 클래스를 수정하지 않고 소스 수정이 가능합니다.

그리고 이렇게 중재자를 사용하면 가독성, 재사용성를 상당히 올릴 수 있습니다.


여기까지 중재자 패턴에 대한 설명이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.