Justin의 개발 로그
article thumbnail

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없지?

 

profile

Justin의 개발 로그

@라이프노트

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!