M개의 object 사이에 N개의 관계가 형성되어 있어 아주 복잡하게 얽혀있을때 이를 M:1 관계로 바꿔주기 위해 중재자 패턴을 사용한다. M개의 object 사이에 이들의 관계를 control 하는 Mediator를 하나 넣어서 Mediator가 모든 object들의 communication을 관리하도록 한다.
- objects들 사이에 Mediator를 넣어 연결관계를 캡슐화한다.
- class들을 loose coupling 상태로 유지할 수 있다. (서로 알 필요 없고 Mediator가 모두 관리하므로)
- 장점 : 전체적인 연결관계를 이해하기 쉽다 (communication의 흐름을 이해하기 쉽다)
- 단점 : 특정 application 로직에 맞춰져있기 때문에 다른 application에 재사용하기 힘들다 (옵저버 패턴의 경우 반대이다. 재사용성은 좋지만 연결관계가 복잡해지면 이해하기 어렵다)
중재자 패턴 vs 옵저버 패턴
- Observer : 재사용성이 좋다. 복잡한 communication에서는 이해하기 힘들다. 1개의 Publisher와 N개의 Subscriber로 이루어져 있다.
- Mediator : 재사용성이 안좋다. 복잡한 communication에서 이해하기 쉽다. M개의 Publisher, N개의 Subscriber 사이의 communication을 1개의 Mediator를 이용해 캡슐화하고 있다.
옵저버 패턴은 1개의 Publisher에 대해 N개의 Subscriber가 존재한다. 즉 복수의 Subscriber가 Publisher의 상태만 관찰하는 셈이다. 그러나 Mediator의 경우 M개의 Publisher와 n개의 Subscriber가 존재한다. 즉 M개의 Publisher가 서로서로 상태를 관찰하기 때문에 Publisher가 Subscriber가 될 수도, Subscriber가 Publisher가 될 수도 있다.
중재자 패턴 예제 - 송신자와 발신자가 다른 케이스
interface ISource{
public void setMediator(Mediator mediator);
public void eventOccured(String event);
}
/*
TcpComm 클래스
ISource를 구현하는 Concrete 부분.
mediator을 설정하고 mediator에게 onEvent로 메시지를 전달한다.
*/
public class TcpComm implements ISource {
Mediator mediator;
@Override
public void setMediator(Mediator mediator){ // 중재자 설정
this.mediator = mediator;
}
@Override
public void eventOccured(String event){ // 이벤트의 전달
mediator.onEvent("TCP comm", event);
}
}
/*
SystemSignal 클래스
TcpComm 클래스와 같다.
*/
class SystemSignal implements ISource{
Mediator mediator;
@Override
public void setMediator(Mediator mediator){ // 중재자 설정
this.mediator = mediator;
}
@Override
public void eventOccured(String event){ // 이벤트의 전달
mediator.onEvent("System", event);
}
}
/*
Mediator 클래스
onEvent를 받으면 해당하는 메시지를 receiveEvent를 통해 보낸다.
*/
import java.util.ArrayList;
import java.util.List;
class Mediator{
List<IDestination> list = new ArrayList<IDestination>();
public void addDestination(IDestination destination){ list.add(destination); }
public void onEvent(String from, String event){
for(IDestination each : list){ // 이벤트의 전송
each.receiveEvent(from, event);
}
}
}
interface IDestination{
public void receiveEvent(String from, String event);
}
class Display implements IDestination{
@Override
public void receiveEvent(String from, String event){
System.out.println("Display : from " + from + " event : " + event);
}
}
class Log implements IDestination{
@Override
public void receiveEvent(String from, String event){
System.out.println("Log : from " + from + " event : " + event);
}
}
/*
MediatorMain 클래스
각 생성자를 만들고 destination은 Display, Log로 해준후 이벤트를 전달하여 아래와 같은 결과값을 얻을 수 있다.
*/
public class MediatorMain {
public static void main(String[] args) {
Mediator mediator = new Mediator();
ISource tcp = new TcpComm();
tcp.setMediator(mediator);
ISource system = new SystemSignal();
system.setMediator(mediator);
mediator.addDestination(new Display());
mediator.addDestination(new Log());
tcp.eventOccured("connected");
tcp.eventOccured("disconnected");
system.eventOccured("key input");
system.eventOccured("mouse input");
}
}
/*
실행결과 >>
Display : from TCP comm event : connected
Log : from TCP comm event : connected
Display : from TCP comm event : disconnected
Log : from TCP comm event : disconnected
Display : from System event : key input
Log : from System event : key input
Display : from System event : mouse input
Log : from System event : mouse input
*/
중재자 패턴 예제 - 송신자와 발신자가 동일 클래스인 케이스
public interface Mediator {
void addUser(Colleague user);
void deleteUser(Colleague user);
void sendMessage(String message, Colleague user);
}
public abstract class Colleague {
protected Mediator mediator;
protected String name;
public Colleague(Mediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}
public abstract void send(String msg);
public abstract void receive(String msg);
}
public class ConcreteMediator implements Mediator {
private final List<Colleague> users;
public ConcreteMediator() {
this.users=new ArrayList<>();
}
@Override
public void addUser(Colleague user) {
this.users.add(user);
}
@Override
public void deleteUser(Colleague user) {
this.users.remove(user);
}
@Override
public void sendMessage(String message, Colleague user) {
for(Colleague u : this.users){
if(u != user){
u.receive(message);
}
}
}
}
public class ConcreteColleague extends Colleague {
public ConcreteColleague(Mediator mediator, String name) {
super(mediator, 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);
}
}
Mediator mediator = new ConcreteMediator();
Colleague user1 = new ConcreteColleague(mediator, "lee");
Colleague user2 = new ConcreteColleague(mediator, "kim");
Colleague user3 = new ConcreteColleague(mediator, "park");
Colleague user4 = new ConcreteColleague(mediator, "yon");
mediator.addUser(user1);
mediator.addUser(user2);
mediator.addUser(user3);
mediator.addUser(user4);
user1.send("안녕하세요");
// lee: Sending Message=안녕하세요
// kim: Received Message:안녕하세요
// park: Received Message:안녕하세요
// yon: Received Message:안녕하세요
mediator.deleteUser(user4);
user2.send("yon없지?");
// kim: Sending Message=yon없지?
// lee: Received Message:yon없지?
// park: Received Message:yon없지?
'프로그래밍 > OOP_Pattern_TDD' 카테고리의 다른 글
디자인패턴 프로토타입 패턴 (Prototype Pattern) (0) | 2022.08.02 |
---|---|
디자인패턴 메멘토 패턴(memento pattern) (0) | 2022.08.02 |
디자인패터 플라이웨이트 패턴 (Flyweight pattern) (0) | 2022.08.01 |
디자인패턴 책임 연쇄 패턴 (chain-of-responsibility pattern) (0) | 2022.08.01 |
디자인패턴 빌더 패턴(Builder Pattern) (0) | 2022.07.29 |