[Design Pattern] 6. Mediator Pattern(중재자 패턴) C#
Mediator개체를 사용하여 다른 개체 간의 통신을 처리해 느슨한 결합을 도와주는 디자인 패턴입니다.
M:N으로 통신을 해야 되거나, 개체 간의 복잡한 상호 작용을 관리하는 데 유용한 패턴입니다.
이 또한 행동 패턴(Behavioral Design Patterns)중 하나입니다.
장점
- 단일 책임 원칙을 족하여 다양한 개체 간의 통신을 한 곳으로 모아 우지 보수를 수월하게 만들 수 있습니다.
- 개방/폐쇄 원칙을 만족하며 기존 코드를 변경하지 않고 새 Mediator를 추가할 수 있습니다.
- 개체들을 재사용하기 수월해 집니다.
- 프로그램의 개체 간의 결합도를 줄일 수 있습니다.
단점
- Mediator 객체가 복잡해지고 기능이 많아져 유지보수가 어렵게 될 수 있습니다.
이번 패턴도 역시 C#으로 Console 프로젝트를 하나 생성해서 할 것입니다.
간단하게 만들겠습니다.
목표는 Mediator에 Moblie 인스턴스를 추가하고 CCTV에 사람이 감지됐을 때 이를 알리는 것입니다.
프로젝트의 tree구조는 아래와 같습니다.
Mediator(Project)
|- Program.cs (Main)
|- IMediator.cs (Mediator Interface)
|- Mediator.cs (Mediator)
|- IReceiveDevice.cs (Destination interface)
|- ITransmitDevice.cs (Source interface)
|- CCTV.cs (Source)
|- Mobile.cs (Destination)
그럼 구현해보겠습니다.
IMediator.cs
namespace Mediator
{
public interface IMediator
{
void Notify(string from, string str_event);
}
}
Notify를 통해 다른 개체에게 어디서(from) 무슨일(str_event)이 일어났는지 알려줄 수 있도록 구성해줍니다.
Mediator.cs
using System.Collections.Generic;
namespace Mediator
{
public class Mediator : IMediator
{
private List<IReceiveDevice> recvDevices = new List<IReceiveDevice>();
public void AddReceiveDevice(IReceiveDevice receiveDevice)
{
recvDevices.Add(receiveDevice);
}
public void Notify(string from, string str_event)
{
foreach (IReceiveDevice receiveDevice in recvDevices)
{
receiveDevice.ReceiveEvent(from, str_event);
}
}
}
}
알려줄 개체들을 List로 관리하기 위해 recvDevices를 만듭니다.
그리고 list에 추가하는 기능과 Notify를 구현해줍니다.
IReceiveDevice.cs
namespace Mediator
{
public interface IReceiveDevice
{
void ReceiveEvent(string from, string str_event);
}
}
내용을 전달받을 수 있게 ReceiveEvent를 구성해줍니다.
ITransmitDevice.cs
namespace Mediator
{
public interface ITransmitDevice
{
void SetMediator(Mediator mediator);
void Notify(string str_event);
}
}
내용을 전달할 수 있게 Mediator를 설정하는 SetMediator와 Notify를 구성해줍니다.
CCTV.cs
namespace Mediator
{
public class CCTV : ITransmitDevice
{
private string name;
private Mediator mediator;
public CCTV(string name)
{
this.name = name;
}
public void Notify(string str_event)
{
mediator.Notify(name, str_event);
}
public void SetMediator(Mediator mediator)
{
this.mediator = mediator;
}
}
}
구별을 위한 name과 전달을 위한 Mediator를 만들어줍니다.
그리고 SetMediator와 Notify를 구현해줍니다.
Mobile.cs
using System;
namespace Mediator
{
public class Mobile : IReceiveDevice
{
private string name;
public Mobile(string name)
{
this.name = name;
}
public void ReceiveEvent(string from, string str_event)
{
Console.WriteLine($"[{name} : {from}]: {str_event}");
}
}
}
구별을 위한 name을 만들고 누가 어디에서 온 메세지를 받았는지 ReceiveEvent에 출력을 해줍니다.
만약 보내고 받고를 다 해야하는 개체가 있다면 ITransmitDevice와 IReceiveDevice를 모두 implements해주면 됩니다.
Program.cs
using System;
namespace Mediator
{
public class Program
{
static void Main(string[] args)
{
Mediator mediator = new Mediator();
Mobile user1 = new Mobile("user1");
Mobile user2 = new Mobile("user2");
mediator.AddReceiveDevice(user1);
CCTV cctv1 = new CCTV("Lounge");
CCTV cctv2 = new CCTV("hall way");
cctv1.SetMediator(mediator);
cctv2.SetMediator(mediator);
cctv1.Notify("Detect People");
Console.WriteLine();
mediator.AddReceiveDevice(user2);
Console.WriteLine("\nafter added user 2");
cctv2.Notify("Detect People");
}
}
}
Mobile인 user1, user2를 만들고 user1만 먼저 추가해줍니다.
CCTV인 cctv1, cctv2를 만들고 Mediator를 설정해줍니다.
cctv1(Lounge)에서 사람이 감지 되었다고 알림을 보냅니다.
user1이 받아서 출력함을 확인 할 수 있으며 아직 user2를 추가하지않아 출력되지 않음을 볼 수 있습니다.
이후 추가해준 뒤
cctv2(hall way)에서 사람이 감지 되었다고 알림을 보냅니다.
user1, user2 모두 정상적으로 출력됨을 확인 할 수 있습니다.
이번에 from, str_event를 다 string으로 했으나 복잡한 상호작용을 구현할 땐 object로 구현하여 데이터를 보내거나 하는 등 구현해서 써봤습니다.
M:N 통신 관계에서 잘사용되는 패턴으로 필요할 때 적용해 보는 것을 추천드립니다.