디자인 패턴

Mediator Pattern

kyoulho 2024. 5. 28. 21:33
728x90

"객체들이 직접 통신하지 않고, 중앙에서 조정해야 할 때!"

  • 중재자 패턴은 객체 간의 직접적인 의존성을 없애고, 중재자를 통해 통신하도록 하는 패턴
  • GUI 이벤트 시스템, 채팅 앱, 항공 관제 시스템 등에서 유용
  • 객체 간의 관계를 단순화하고 유지보수를 쉽게 만들지만, 중재자가 너무 커지지 않도록 주의해야 함

📌 중재자 패턴의 핵심 개념

  1. Mediator (중재자 인터페이스)
    • 객체들 간의 통신을 조정하는 인터페이스 역할
    • Component(객체)들이 직접 통신하지 않고 Mediator를 통해 간접적으로 소통함
  2. ConcreteMediator (구체적인 중재자)
    • Mediator를 구현한 클래스
    • 여러 Component 간의 관계를 관리하고, 이벤트를 중재함
  3. Component (구성 요소)
    • 서로 직접 연결되지 않고 Mediator를 통해서만 통신하는 개별 객체
    • Mediator를 통해서만 메시지를 보내고 받음

📌 중재자 패턴의 UML

        +-------------------+
        |     Mediator      |
        |-------------------|
        | + notify(sender)  |
        | + register(comp)  |
        +-------------------+
                  ▲
                  │
  +--------------------------+
  |   ConcreteMediator       |
  |--------------------------|
  | + notify(sender)         |
  | + register(comp)         |
  +--------------------------+
           ▲          ▲
           │          │
+----------+--+    +--+----------+
| ComponentA  |    | ComponentB  |
|------------|    |------------|
| + notify() |    | + notify() |
| + send()   |    | + send()   |
+------------+    +------------+

📌 중재자 패턴 예제 코드 (Java)

1. Mediator 인터페이스

// 중재자 인터페이스
interface Mediator {
    void notify(Component sender, String event);
    void register(Component component);
}

2. Component 클래스 (중재자를 이용해 통신)

// 모든 컴포넌트의 기본 클래스
abstract class Component {
    protected Mediator mediator;

    public Component(Mediator mediator) {
        this.mediator = mediator;
        mediator.register(this); // 중재자에 등록
    }

    public abstract void send(String event);
    public abstract void receive(String event);
}

3. ConcreteComponent 클래스 (실제 컴포넌트)

// 구체적인 컴포넌트 A
class Button extends Component {
    public Button(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void send(String event) {
        System.out.println("🔘 버튼이 클릭됨");
        mediator.notify(this, event);
    }

    @Override
    public void receive(String event) {
        System.out.println("🔘 버튼이 이벤트를 수신: " + event);
    }
}

// 구체적인 컴포넌트 B
class TextBox extends Component {
    public TextBox(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void send(String event) {
        System.out.println("📝 텍스트가 입력됨");
        mediator.notify(this, event);
    }

    @Override
    public void receive(String event) {
        System.out.println("📝 텍스트 박스가 이벤트를 수신: " + event);
    }
}

4. ConcreteMediator 클래스 (중재자 역할)

import java.util.ArrayList;
import java.util.List;

// 중재자 구현 클래스
class FormMediator implements Mediator {
    private List<Component> components = new ArrayList<>();

    @Override
    public void register(Component component) {
        components.add(component);
    }

    @Override
    public void notify(Component sender, String event) {
        for (Component component : components) {
            if (component != sender) {
                component.receive(event);
            }
        }
    }
}

5. 사용 예시

public class MediatorPatternExample {
    public static void main(String[] args) {
        Mediator mediator = new FormMediator();

        Button button = new Button(mediator);
        TextBox textBox = new TextBox(mediator);

        // 버튼이 클릭되면 TextBox에도 영향을 줌
        button.send("버튼 클릭 이벤트 발생");

        System.out.println("------------------");

        // 텍스트 박스 입력이 변경되면 다른 컴포넌트에게 전달됨
        textBox.send("텍스트 입력 이벤트 발생");
    }
}

📌 실행 결과

🔘 버튼이 클릭됨
📝 텍스트 박스가 이벤트를 수신: 버튼 클릭 이벤트 발생
------------------
📝 텍스트가 입력됨
🔘 버튼이 이벤트를 수신: 텍스트 입력 이벤트 발생

📌 중재자 패턴의 장단점

장점

  1. 객체 간의 의존성을 줄임 (Loosely Coupled)
    • Component들이 서로 직접 통신하지 않고 Mediator를 통해 소통하여 결합도가 낮아짐
    • 유지보수가 쉬워지고 확장성이 높아짐
  2. 객체 간의 직접적인 관계를 제거하여 복잡성을 감소
    • 컴포넌트가 서로 알 필요 없이 Mediator를 통해 메시지를 주고받음
    • 코드의 가독성이 증가하고 디버깅이 쉬워짐
  3. 객체 추가/변경이 쉬움
    • 새로운 컴포넌트 추가 시 기존 컴포넌트 수정 없이 Mediator에만 등록하면 됨

단점

  1. 중재자가 너무 많은 역할을 하게 될 가능성
    • 모든 메시지를 처리하다 보면 Mediator가 거대한 객체가 되어 유지보수 어려움
    • 이를 해결하려면 Mediator를 여러 개로 분리할 수도 있음
  2. 구현이 다소 복잡할 수 있음
    • 단순한 경우에는 굳이 Mediator를 도입할 필요 없이 직접 통신하는 것이 효율적일 수 있음

📌 중재자 패턴을 사용해야 할 때

적합한 경우

  • 여러 개의 객체가 서로 복잡하게 연결되어 있는 경우
  • 컴포넌트 간의 상호작용을 중앙에서 관리하고 싶을 때
  • 객체 간의 의존성을 낮추고 독립적으로 확장하고 싶을 때

적합하지 않은 경우

  • 컴포넌트가 적고 관계가 단순한 경우 (불필요한 복잡성 증가)
  • Mediator가 너무 커지는 경우 오히려 유지보수가 어려워질 수 있음

📌 중재자 패턴이 사용되는 예시

  1. GUI 이벤트 시스템
    • 버튼, 입력 필드, 체크박스 등이 직접 소통하지 않고 Mediator를 통해 통신
    • 예: 버튼 클릭 → Mediator가 폼 검증 후 제출 버튼 활성화
  2. 채팅 애플리케이션
    • 사용자가 개별적으로 메시지를 주고받는 것이 아니라 채팅 서버(중재자)가 메시지를 중개
  3. 항공 교통 관제 시스템
    • 비행기들끼리 직접 통신하지 않고 관제탑(중재자) 을 통해 정보를 교환
728x90

'디자인 패턴' 카테고리의 다른 글

Proxy Pattern  (0) 2024.06.15
Observer Pattern  (0) 2024.05.30
Iterator Pattern  (0) 2024.05.27
Flyweight Pattern  (0) 2024.05.25
Factory Pattern  (0) 2024.05.18