안녕하세요! GoF 디자인 패턴 연재, 이번 시간에는 행위 패턴(Behavioral Patterns)의 한 종류로, 여러 객체 간의 복잡한 상호작용(M-to-M 관계)을 하나의 중재자 객체에 캡슐화하여 관리하는 중재자(Mediator) 패턴에 대해 알아보겠습니다.
정의
중재자 패턴은 시스템에 존재하는 다수의 객체(Colleague)들 간의 복잡한 상호작용을 중재자(Mediator)라는 하나의 객체에 집중하여 처리하도록 만드는 패턴입니다. 객체들은 더 이상 서로를 직접 참조하지 않고, 오직 중재자를 통해서만 소통합니다.
항공 관제탑을 생각하면 가장 이해하기 쉽습니다.
- 수많은 비행기(Colleague 객체들)들이 공항에 착륙하거나 이륙하기 위해 서로의 위치, 속도, 경로를 파악해야 한다면 매우 복잡하고 위험할 것입니다. 모든 비행기가 다른 모든 비행기와 직접 통신해야 하니까요.
- 하지만 항공 관제탑(Mediator 객체)이 있으면, 모든 비행기는 관제탑하고만 통신하면 됩니다. 관제탑은 모든 비행기의 정보를 종합하여 각 비행기에게 착륙 허가, 경로 변경 등의 지시를 내립니다.
이처럼 중재자 패턴은 객체들 간의 직접적인 연결(거미줄 같은 M-to-M 관계)을, 중재자를 통한 간접적인 연결(성형(Star) 구조의 1-to-M 관계)로 바꾸어 시스템의 복잡도를 낮추고 결합도를 줄여줍니다.
중재자(Mediator)와 동료(Colleague)가 중심이 되어 다음과 같은 구성요소를 가집니다.
- Mediator (중재자): Colleague 객체들과 통신하기 위한 인터페이스를 정의합니다.
- ConcreteMediator (구체적인 중재자): Mediator 인터페이스를 구현하며, 모든 Colleague 객체들을 알고 있습니다. Colleague들 간의 통신을 조정하고 중재하는 역할을 합니다.
- Colleague (동료): 다른 Colleague와 통신해야 하는 객체들의 인터페이스입니다. Mediator 객체에 대한 참조를 가집니다.
- ConcreteColleague (구체적인 동료): Colleague 인터페이스를 구현합니다. 자신의 상태가 변하거나 다른 Colleague에게 메시지를 보내야 할 때, Mediator에게 알립니다.
사용예시
여러 사용자가 참여하는 채팅방 시스템을 중재자 패턴으로 구현해 보겠습니다.
1. 중재자 (Mediator) 및 동료 (Colleague) 인터페이스/추상 클래스 정의
먼저 채팅방(중재자)과 사용자(동료)의 기반이 될 인터페이스와 추상 클래스를 정의합니다.
// Mediator 인터페이스
interface ChatMediator {
void sendMessage(String msg, User user);
void addUser(User user);
}
// Colleague 추상 클래스
abstract class User {
protected ChatMediator mediator;
protected String name;
public User(ChatMediator med, String name){
this.mediator = med;
this.name = name;
}
public abstract void send(String msg);
public abstract void receive(String msg);
}
2. 구체적인 중재자 (ConcreteMediator) 클래스 구현
실제 채팅방의 역할을 하는 ChatRoom 클래스를 구현합니다.
import java.util.ArrayList;
import java.util.List;
// ConcreteMediator 클래스
public class ChatRoom implements ChatMediator {
private List<User> users;
public ChatRoom(){
this.users = new ArrayList<>();
}
@Override
public void addUser(User user){
this.users.add(user);
}
@Override
public void sendMessage(String msg, User user) {
// 메시지를 보낸 사용자를 제외한 모든 사용자에게 메시지 전송
for(User u : this.users){
if(u != user){
u.receive(msg);
}
}
}
}
3. 구체적인 동료 (ConcreteColleague) 클래스 구현
채팅에 참여하는 실제 사용자를 구현합니다.
// ConcreteColleague 클래스
public class ChatUser extends User {
public ChatUser(ChatMediator med, String name) {
super(med, name);
}
@Override
public void send(String msg){
System.out.println(this.name + ": Sending Message = " + msg);
mediator.sendMessage(msg, this);
}
@Override
public void receive(String msg) {
System.out.println(this.name + ": Received Message: " + msg);
}
}
4. 클라이언트 (Client) 코드
클라이언트는 중재자와 동료 객체들을 생성하고 연결합니다.
public class ChatClient {
public static void main(String[] args) {
// 1. 중재자(채팅방) 생성
ChatMediator mediator = new ChatRoom();
// 2. 동료(사용자)들 생성 및 채팅방에 추가
User user1 = new ChatUser(mediator, "Alice");
User user2 = new ChatUser(mediator, "Bob");
User user3 = new ChatUser(mediator, "Charlie");
mediator.addUser(user1);
mediator.addUser(user2);
mediator.addUser(user3);
// 3. 사용자가 메시지 전송
user1.send("안녕하세요!");
// 실행 결과:
// Alice: Sending Message = 안녕하세요!
// Bob: Received Message: 안녕하세요!
// Charlie: Received Message: 안녕하세요!
}
}
결론
중재자 패턴은 1:M관계를 단순화하는 효율적인 패턴으로 다음과 같은 경우에 사용됩니다.
- 다수의 객체들이 서로 복잡하게 통신하여 결합도가 너무 높아질 때: 객체 간의 직접적인 연결을 없애고 중재자를 통해 통신하게 함으로써 결합도를 낮출 수 있습니다.
- 한 객체의 변경이 다른 많은 객체들의 변경을 초래하는 경우: 중재자를 사용하면 각 `Colleague`는 독립적으로 변경할 수 있고, 통신 방식의 변경은 `Mediator`만 수정하면 됩니다.
- 재사용하기 어려운 객체를 상속 대신 중재자를 통해 재사용하고 싶을 때
그러나, 모든 통신이 중재자에 집중되므로, 시스템이 복잡해질수록 중재자 객체 자체가 매우 복잡해지고 거대해질 수 있습니다. (God Object 안티 패턴)
중재자 패턴은 복잡한 객체 관계망을 단순하고 관리하기 쉬운 구조로 만들어주는 효과적인 방법입니다. 객체 간의 상호작용 로직을 한 곳에 모아 응집도를 높이고, 각 객체는 자신의 역할에만 충실하게 만들어줍니다. 다음시간에는 Memento 패턴에 대해서(메멘토 MOOORI) 알아보겠습니다!
'정보보안-이론 > XX에 대하여' 카테고리의 다른 글
[디자인 패턴] (GoF 행위패턴) Iterator Pattern에 대하여 (0) | 2025.07.11 |
---|---|
[디자인 패턴] (GoF 행위패턴) Memento Pattern에 대하여 (0) | 2025.07.11 |
[디자인 패턴] (GoF 행위패턴) Chain of Responsibility Pattern에 대하여 (0) | 2025.07.10 |
[디자인 패턴] (GoF 구조패턴) Proxy Pattern에 대하여 (0) | 2025.07.09 |
[디자인 패턴] (GoF 행위패턴) Command Pattern에 대하여 (0) | 2025.07.09 |