본문 바로가기
Design Pattern

[Design Pattern] Mediator Pattern

by Jiseong 2022. 3. 20.

Mediator Pattern

객체간의 종속성을 줄일 수 있는 패턴으로, 여러 Colleague들 사이를 Mediate하는 역할을 하는 인터페이스가 존재한다.

 

클래스간의 종속을 줄이기위해 클래스 사이에 Mediator가 존재하고, 여러 클래스들은 서로 직접 참조, 통신하는 것이 아닌 Mediator를 통해서 메세지를 주고 받는다.

 

Use When?

  • 객체들간의 상호작용 관계가 복잡할 때

 

다이어그램을 통해 알아보자

Mediator Pattern을 통해 객체간 종속성을 줄이기 전의 다이어그램이다.

 

서로 강하게 참조를 하고있으며, M:N 관계로 상호간 매우 얽혀있는 모습을 볼 수 있다.

 

이때 클래스 간의 복잡한 관계들을 캡슐화하여 하나의 클래스에서 관리하도록 한다.

 

M:N의 관계를 Mediator Pattern을 통해 M:1 관계로 만들어 복잡성을 내림으로써 유지 보수 및 확장성에 유리하다.

 

저 통신 관계간에 새로운 객체를 추가하고 싶다면, Colleague를 추상화하여 새로운 객체가 해당 프로토콜을 채택하면 통신 관계에 쉽게 낄 수 있다.

 

이렇게 M개의 객체(Colleague)들 사이에 중재자(Mediator)를 둠으로써 모든 객체들의 통신을 담당하도록 변경하는 것을 Mediator Pattern이라고 하며, 해당 패턴을 사용하면 각 객체들은 서로 종속되지 않고, Mediator가 관리하므로 객체들간의 커플링(결합)을 느슨하게 할 수 있다.

 

Observer Pattern과 비슷한데, 차이점은 다음과 같다.

Observer Pattern은 1개의 Publisher가 존재하고, 여러 Subscriber가 1개의 Publisher를 관찰하는 형태이다.

 

하지만 Mediator Pattern의 경우 M개의 Publisher와 N개의 Subscriber가 존재하고, Publisher와 Subscriber가 1개의 Mediator를 통해 통신하는 방식이다.

서로가 서로의 상태를 관찰하기 때문에 Publisher가 Subscriber가 될 수 있고, Subscriber가 Publisher가 될 수 있다.

 

예제

 

실제 코드를 보며 살펴보자

Colleague는 Mediator를 통하여 통신할 수 있고, Colleague끼리 직접 통신할 순 없다. 하지만 특정 Mediator만을 고집하는 Colleague, 특정 Colleague만 고집하는 Mediator가 있다면 이 역시 종속성이 있는 구조이기 때문에 추상화를 해줘야한다.

 

먼저 Mediator와 의 Colleague역할을 생각하며 추상화를 해보자

 

Mediator의 역할은 Colleague에게 온 메세지를 Colleague에게 보내야한다.

 

그렇기에 Mediator은 Colleague를 알아야하고, 메세지 내용 또한 알아야한다.

 

그리고 Colleague의 역할은 메세지를 보내고, 받아야하며 Colleague끼리 직접 통신은 불가하기때문에 Mediator를 알아야한다.

protocol MediatorProtocol: AnyObject {
    var colleages: [ColleageProtocol] { get }
    func send(_ message: String, by colleage: ColleageProtocol)
}

protocol ColleageProtocol: AnyObject {
    var mediator: MediatorProtocol { get }
    func send(_ message: String)
    func receive(_ message: String)
}

이제 해당 프로토콜을 채택하는 클래스들을 만들어보자

class Mediator: MediatorProtocol {
    
    var colleages: [ColleageProtocol] = []
    
    func send(_ message: String, by colleage: ColleageProtocol) {
        colleages
            .filter { $0 !== colleage }
            .forEach { $0.receive(message) }
    }
}

class Colleague1: ColleageProtocol {
    
    var mediator: MediatorProtocol
    
    init(mediator: MediatorProtocol) {
        self.mediator = mediator
    }
    
    func send(_ message: String) {
        self.mediator.send(message, by: self)
    }
    
    func receive(_ message: String) {
        print("나 \(self)임, \(message) 이렇게 메세지 옴 ㅋㅋ")
    }
}

class Colleague2: ColleageProtocol {
    
    var mediator: MediatorProtocol
    
    init(mediator: MediatorProtocol) {
        self.mediator = mediator
    }
    
    func send(_ message: String) {
        self.mediator.send(message, by: self)
    }
    
    func receive(_ message: String) {
        print("나 \(self)임, \(message) 이렇게 메세지 옴 ㅋㅋ")
    }
}

Mediator 클래스의 send 메서드 내부를 보면 메세지를 보낸 Colleague를 제외한 사람한테 메세지를 보내는 것을 알 수 있다.

 

실행해보면..

 

func run() {
    let mediator = Mediator()
    let colleague1 = Colleague1(mediator: mediator)
    let colleague2 = Colleague2(mediator: mediator)
    
    mediator.colleages += [colleague1, colleague2]
    
    colleague1.send("ㅎㅇ 나 \(colleague1)임")
}

run()

;; 플레이그라운드

일케 온다.

 

해당 패턴의 장단점은 다음과 같다.

 

장점

  • 단일 책임 원칙 - Mediator은 Colleague에게 온 메세지를 전달해주는 역할, Colleague는 메세지를 보내고 받는 역할을 하므로 역할이 정해져있어 코드 이해가 쉽고 그로인해 유지보수가 쉬워진다.
  • 개방 폐쇄 원칙 - 예제처럼 추상화를 진행한다면, 위에서도 말했듯이 통신에 새로운 객체가 껴도 이전 코드엔 영향이 없고, 새로 끼고, 빠지기도 쉬워진다.
  • 객체간 종속성 감소

 

단점

  • 모든 메세지가 Mediator를 거쳐서 통신되므로 코드가 쌓일수록 방대해질 가능성이 있다. (God Object)

 

https://reactiveprogramming.io/blog/en/design-patterns/mediator

https://brunch.co.kr/@yoonms/29

'Design Pattern' 카테고리의 다른 글

[Design Pattern] Coordinator Pattern  (0) 2022.07.29
[Design Pattern] Singleton Pattern  (0) 2022.03.31

댓글