Design Pattern

[Design Pattern] 6. Mediator Pattern(중재자 패턴) C#

o0zrone 2023. 3. 26. 23:03
728x90

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 통신 관계에서 잘사용되는 패턴으로 필요할 때 적용해 보는 것을 추천드립니다.