미디에이터 패턴(Mediator Pattern) 이해하기
미디에이터 패턴은 객체 간의 복잡한 상호작용을 캡슐화하여, 객체 간의 결합도를 낮추는 행동 디자인 패턴입니다. 이 패턴은 객체들이 서로 직접 통신하는 대신 중재자(Mediator) 객체를 통해 간접적으로 통신하도록 하여, 객체 간의 의존성을 줄이고 시스템의 유연성을 높입니다.
미디에이터 패턴은 특히 여러 객체가 서로 상호작용해야 하는 복잡한 시스템에서 유용하며, 객체 간의 의존 관계를 단순화하여 유지보수와 확장성을 높이는 데 도움을 줍니다.
미디에이터 패턴이란?
미디에이터 패턴은 객체 간의 상호작용을 중재하는 객체(미디에이터)를 도입하여, 객체들이 서로 직접적으로 참조하거나 통신하지 않도록 만드는 디자인 패턴입니다. 이 패턴은 각 객체가 미디에이터 객체와만 통신하며, 미디에이터가 상호작용을 관리하고 중재합니다.
주요 개념은 직접적인 의존성을 제거하고 객체 간의 결합도를 낮추는 것입니다. 이를 통해 시스템은 더 유연하고 확장 가능해집니다.
미디에이터 패턴의 구조
미디에이터 패턴은 다음과 같은 구성 요소로 이루어집니다.
- Mediator (중재자 인터페이스):
- 객체 간의 통신을 중재하는 인터페이스를 정의합니다.
- ConcreteMediator (구체적인 중재자):
- Mediator 인터페이스를 구현하며, 객체 간의 상호작용을 구체적으로 관리합니다.
- Colleague (동료 인터페이스):
- 미디에이터와 상호작용하는 객체의 공통 인터페이스를 정의합니다.
- ConcreteColleague (구체적인 동료 객체):
- Colleague 인터페이스를 구현하며, 미디에이터를 통해 다른 객체와 통신합니다.
미디에이터 패턴의 구현 방법
예제 코드: 채팅방 구현
다음은 미디에이터 패턴을 활용하여 **채팅방(Chat Room)**을 구현한 예제입니다. 채팅방은 사용자 간의 메시지 전달을 중재하는 역할을 합니다.
// Mediator 인터페이스
public interface IChatRoom
{
void SendMessage(string message, string userId);
void RegisterUser(User user);
}
// ConcreteMediator 클래스: 채팅방
public class ChatRoom : IChatRoom
{
private Dictionary<string, User> _users = new Dictionary<string, User>();
public void RegisterUser(User user)
{
if (!_users.ContainsKey(user.Id))
{
_users[user.Id] = user;
user.SetChatRoom(this);
}
}
public void SendMessage(string message, string userId)
{
if (_users.ContainsKey(userId))
{
_users[userId].Receive(message);
}
}
}
// Colleague 클래스
public abstract class User
{
protected IChatRoom _chatRoom;
public string Id { get; }
public string Name { get; }
public User(string id, string name)
{
Id = id;
Name = name;
}
public void SetChatRoom(IChatRoom chatRoom)
{
_chatRoom = chatRoom;
}
public void Send(string message, string userId)
{
Console.WriteLine($"{Name} sends: {message} to {userId}");
_chatRoom.SendMessage(message, userId);
}
public abstract void Receive(string message);
}
// ConcreteColleague 클래스: 일반 사용자
public class NormalUser : User
{
public NormalUser(string id, string name) : base(id, name) { }
public override void Receive(string message)
{
Console.WriteLine($"{Name} received: {message}");
}
}
// 클라이언트 코드
class Program
{
static void Main()
{
// Mediator 생성
IChatRoom chatRoom = new ChatRoom();
// Colleague 객체 생성 및 등록
User user1 = new NormalUser("1", "Alice");
User user2 = new NormalUser("2", "Bob");
User user3 = new NormalUser("3", "Charlie");
chatRoom.RegisterUser(user1);
chatRoom.RegisterUser(user2);
chatRoom.RegisterUser(user3);
// 메시지 전송
user1.Send("Hello Bob!", "2");
user2.Send("Hi Alice!", "1");
user3.Send("Hey everyone!", "1");
}
}
실행 결과
Alice sends: Hello Bob! to 2
Bob received: Hello Bob!
Bob sends: Hi Alice! to 1
Alice received: Hi Alice!
Charlie sends: Hey everyone! to 1
Alice received: Hey everyone!
코드 설명
- Mediator:
- IChatRoom 인터페이스는 사용자 간의 메시지 전달을 중재하는 역할을 합니다.
- ConcreteMediator:
- ChatRoom 클래스는 IChatRoom을 구현하며, 메시지 전달과 사용자 등록을 관리합니다.
- Colleague:
- User 클래스는 미디에이터와 상호작용하는 기본 사용자 인터페이스를 제공합니다.
- ConcreteColleague:
- NormalUser 클래스는 User를 상속받아 채팅 메시지를 보내고 받을 수 있는 기능을 구현합니다.
미디에이터 패턴의 장단점
장점
- 객체 간 결합도 감소:
- 객체 간의 직접적인 의존성을 제거하여 시스템의 결합도를 낮출 수 있습니다.
- 유지보수성 향상:
- 객체 간의 상호작용이 미디에이터에 캡슐화되어 있어, 새로운 객체를 추가하거나 상호작용을 변경하기 쉽습니다.
- 중앙화된 통제:
- 미디에이터 객체를 통해 상호작용을 중앙에서 관리할 수 있어, 복잡한 상호작용을 단순화할 수 있습니다.
단점
- 미디에이터의 복잡성 증가:
- 미디에이터가 너무 많은 책임을 가지게 되면, 복잡도가 증가하고 코드가 난해해질 수 있습니다.
- 의존성 전이:
- 객체 간의 의존성이 미디에이터로 이전되므로, 미디에이터가 단일 실패 지점(Single Point of Failure)이 될 수 있습니다.
언제 미디에이터 패턴을 사용해야 할까?
미디에이터 패턴은 다음과 같은 상황에서 유용합니다.
- 객체 간 상호작용이 복잡할 때:
- 여러 객체가 서로 상호작용해야 하며, 이를 중앙에서 관리하여 복잡도를 줄이고 싶을 때.
- 객체 간 결합도를 줄이고 싶을 때:
- 객체 간의 직접적인 참조를 제거하고, 간접적인 통신을 통해 결합도를 낮추고 싶을 때.
- 상호작용 로직이 자주 변경될 때:
- 객체 간의 상호작용이 자주 변경되거나 추가될 가능성이 높은 경우.
미디에이터 패턴과 관련 패턴 비교
미디에이터 패턴은 객체 간의 상호작용을 캡슐화하여 결합도를 줄이는 데 초점을 둡니다. 다른 패턴과의 차이를 살펴보겠습니다.
- 옵저버 패턴:
- 객체 간의 일대다 관계를 정의하여 상태 변경을 자동으로 알립니다. 미디에이터 패턴과 달리, 객체 간 직접적인 연결을 허용합니다.
- 책임 연쇄 패턴:
- 요청을 처리할 객체를 체인 형태로 연결합니다. 미디에이터 패턴은 중앙집중식 통제를 제공하는 반면, 책임 연쇄 패턴은 요청을 분산 처리합니다.
- 퍼사드 패턴:
- 복잡한 서브시스템을 단순화하여 단일 인터페이스를 제공합니다. 퍼사드 패턴은 시스템의 구조적 단순화를 목표로 하며, 객체 간의 상호작용에는 초점을 두지 않습니다.
실무에서 미디에이터 패턴 활용하기
미디에이터 패턴은 다음과 같은 상황에서 활용됩니다.
- UI 이벤트 처리:
- 버튼, 텍스트 필드 등 여러 UI 컴포넌트 간의 상호작용을 미디에이터로 중앙 관리.
- 채팅 시스템:
- 사용자 간 메시지 전달을 중재하는 채팅방 구현.
- 게임 시스템:
- 캐릭터, 아이템, 환경 간의 상호작용 관리.
- 분산 시스템:
- 여러 노드 간의 메시지 교환 및 동기화를 관리하는 메시지 브로커 역할.
마무리하며
미디에이터 패턴은 객체 간의 상호작용을 중앙에서 관리하여 결합도를 낮추고, 시스템의 복잡성을 줄이는 데 유용한 패턴입니다. 특히 상호작용이 복잡하거나, 객체 간의 직접적인 의존성을 제거해야 하는 상황에서 큰 효과를 발휘합니다.
객체 간의 상호작용을 단순화하고 유지보수성을 높이고 싶다면, 미디에이터 패턴을 적극적으로 활용해보세요. 이를 통해 시스템의 유연성과 확장성을 크게 향상시킬 수 있습니다.
'Thinking > Concept' 카테고리의 다른 글
옵저버 패턴(Observer Pattern) 이해하기 (0) | 2024.11.17 |
---|---|
메멘토 패턴(Memento Pattern) 이해하기 (1) | 2024.11.16 |
이터레이터 패턴(Iterator Pattern) 이해하기 (0) | 2024.11.16 |
인터프리터 패턴(Interpreter Pattern) 이해하기 (0) | 2024.11.16 |
커맨드 패턴(Command Pattern) 이해하기 (0) | 2024.11.16 |