제 홈페이지의 모든 글은 anti-nhn license에 따릅니다.



자바 디자인 패턴 15 - Mediator

1. Mediator 패턴은..

비행기가 이착륙하다가 충돌하는 일은 좀체로 일어나지 않습니다. 비행기들끼리 서로 통신하지 않는데도 말이죠. 각각의 비행기는 관제탑하고만 통신을 하고, 관제탑이 각각의 비행기에게 착륙해도 된다 또는 안 된다 식으로 메시지를 보내줍니다. 비행기들끼리 서로서로 직접 통신을 한다면 통신할 경우의 수가 무진장 많아져서 혼란스럽게 됩니다. Mediator 패턴은 관제탑과 같이 통신을 집중시킴으로써 통신의 경로를 줄이고 단순화시키는 역할을 합니다.

2. 예제

------------------ 관제탑 역할을 하는 ControlTower (활주로 역할도 함) ----------------
package ch15_Mediator;

public class ControlTower {
    private volatile  boolean inUse;
   
    public synchronized boolean getPermission(){
        if (inUse) {
            return false;
        }else{
            inUse = true;
            return true;
        }
    }
   
    public void land(Airplane airplane) throws InterruptedException{
        int seq = airplane.getSeq();
        System.out.println(seq +"번 비행기 착륙 시작");
        Thread.sleep(50L);
        System.out.println(seq + "번 비행기 착륙 끝");
        inUse = false;
    }
}
------------------ 착륙허가를 받아야하는 Airplane ----------------
package ch15_Mediator;

public class Airplane extends Thread {
    private final ControlTower tower;
    private final int seq;

    public Airplane(ControlTower tower, int seq) {
        this.tower = tower;
        this.seq = seq;
    }

    public int getSeq() {
        return seq;
    }

    @Override
    public void run() {
        try {
            while (!tower.getPermission()) {
                // System.out.println(seq +"번 째 비행기 대기 중.");
                Thread.sleep(10L);
            }
            tower.land(this);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

------------------ 테스트 클래스 ----------------
package ch15_Mediator;

public class Test {
    public static void main(String[] args) {
        ControlTower tower = new ControlTower();
        Airplane[] airplanes = new Airplane[10];
        for (int i = 0; i < airplanes.length; i++) {
            airplanes[i] = new Airplane(tower, i);
        }
        for (Airplane airplane : airplanes) {
            airplane.start();
        }
    }
}

위 프로그램을 실행시키면, 비행기가 동시에 활주로를 사용하는 일은 발생하지 않습니다. 10대의 비행기는 모두 ControlTower를 가지고 있는데, 이는 동일한 ControlTower입니다. 즉, 비행기들끼리는 통신하지 않고 관제탑하고만 통신해서 충돌을 방지하게 되는 것입니다.
위의 예제에서 ControlTower는 모든 통신의 중계 역할을 합니다. 이를 Mediator(중계자)라 합니다. 그리고, Airplane은 Mediator와 통신을 하는 역할을 합니다. 이를 Colleague(사전적인 의미는 동료이지만, Mediator와 통신하는 객체들이라고 생각하시면 됩니다.) 라고 합니다.

위의 예제를 좀 더 확장해서 생각해 봅시다.

첫번째로 Airplane 은 ControlTower가 한 번 세팅이 되면 바꿀 방법이 없습니다. 위의 예제만으로는 비행기는 일회용이겠죠. 다른 공항에 착륙하고자할 때는 비행기가 통신할 관제탑이 바뀔 수도 있습니다. 그래서 보통은 Colleague 클래스는 setMediator 와 같은 메쏘드를 가지고 있습니다.

두번째로는 callback입니다. 예제에서는 비행기들이 관제탑에 "나 착륙해도 되?" 라고 계속 물어봅니다. "된다"라는 대답을 들을 때까지! 관제탑에서는 정신없습니다. (녹색부분의 주석을 풀어보면 얼마나 정신없는 지 바로 보입니다.)  
질문 방식을 바꾸면 어떨까요? 비행기가 "나 착륙할라고 하는데 활주로 비면 연락줘. 기둥기께" 라고 관제탑에 메시지를 보내고 관제탑은 그 비행기를 착륙 대기 리스트에 추가시켜 놓고, 리스트 앞에서 부터 각각의 비행기에게 "너 인제 착륙해도 된다"는 메시지를 보내면 됩니다. 이렇게 하면 통신 횟수를 확 줄일 수 있습니다.
callback은 명령을 내리고 임무를 완료하면 다시 연락하라는 겁니다. 짜장면 주문을 예로 들어보겠습니다. 짜장면집에 전화를 걸고, 주문을 합니다. 우리는 짜장면이 올 때까지 딴짓을 합니다. 짜장면이 배달오면 배달원이 초인종을 누릅니다. "주문" 이 명령이고, "배달"이 임무 완료입니다. "내"가 "짜장면집"에 명령을 하고 "짜장면집"은 그 명령을 수행합니다. "짜장면집"이 임무를 완수하면 "나"한테 "다시 연락"을 줍니다. 임무가 수행되는 동안 "나"는 "짜장면집"에서 짜장면을 잘 만들고 있는 지 신경을 쓰지 않습니다.

 세번째는 활주로가 1개 뿐이라는 겁니다. 활주로가 여러개라면 Runway 라는 활주로 클래스를 만들어야 합니다. 이 활주로는 당연히 ControlTower와 통신을 해야 합니다.  ControlTower가 어떤 비행기가 착륙 요청했다는 정보를 활주로에 알려주고, 비행기한테는 어떤 활주로에 착륙해라 라고 비행기와 활주로 사이에 관계를 맺어줍니다. 실제 착륙 작업에서는 더 이상 관제탑이 관여할 게 없습니다. 다만, 착륙이 완료 되면 활주로한테 이제 활주로가 다시 사용가능하다는 callback은 받아야겠죠.
이 경우 Runwary도 Colleague가 되어야 합니다. Colleague는 한 가지 특정타입(예제의 경우 Airplane)으로 국한될 필요는 없습니다.
Airplane의 getPermission은 getAvailableRunway로 바뀌고 리턴 타입역시 Runway로 바뀌어야겠습니다. 사용가능한 활주로가 없을 때는 null을 리턴한다거나 하면 되겠습니다.
그리고 land 메쏘드도 ControlTower가 아닌 Runway로 옮겨가야겠지요. 그리고 land 안에는 ControlTower에게 착륙이 끝났다는 정보를 전달할 수 있는 로직이 필요합니다.

3. 수 많은 Adapter가 필요한 경우

A,B,C 3개 회사가 합병을 했다 칩시다. 각각의 회원 정보를 다음과 같은 인터페이스로 정의해서 사용합니다.

interface ACompanyUser{     String getName();  }
interface BCompanyUser{     String getName();  }
interface CCompanyUser{     String getName();  }

이제 하나가 된 만큼 회원 정보를 서로 공유해야 하는데, 각 회사의 시스템은 예전 자기 회사의 인터페이스만을 받아들이도록 되어있습니다. 서로 캐스팅이 불가능한 객체를 캐스팅하고 싶을 때 Adapter 패턴을 씁니다. 다음과 같은 6개의 Adapter가 필요합니다.

AToBUser
AToCuser
BToAUser
BToCUser
CToAUser
CToBUser

아... 복잡해지기 시작합니다. 중계 객체를 하나 두면 어떨까요? 중계 객체를 M이라 합시다. 즉, A에서 B로 바꾸려면 위에서는 AToBUser 를 통해서 바꾸면 되었지만, 이제 AToM , MToB와 같이 두 단계를 거쳐서 만들면 됩니다. 단계가 늘어났지만 뭔가 좋은 게 있을 겁니다.

AToM
BToM
CToM
MToA
MToB
MToC

얼레? 똑같이 6갭니다. 그러나 갯수가 많아지면 얘기가 달라집니다. N개의 회사가 있다고 하면, 직접 변환을 할 경우 N*(N-1) 개의 인터페이스가 필요합니다. 그러나, 중계 객체를 만들면 2*N개만 있으면 됩니다. 4개의 회사의 경우 12개 - 8개 , 5개 회사는 20개-10개 와 같이 갯수가 많아 질수록 중계 객체를 두는 게 유리해집니다.

by 삼실청년 | 2009/02/16 23:24 | 컴터질~ | 트랙백 | 핑백(2) | 덧글(6)

트랙백 주소 : http://iilii.egloos.com/tb/4850510
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Linked at java design patt.. at 2017/05/31 09:26

... 15. 자바 디자인 패턴 15 – Mediator ... more

Linked at 자바 디자인 패턴 종류 &#8.. at 2017/09/26 09:15

... 패턴 12 – Prototype 13. 자바 디자인 패턴 13 – Flyweight 14. 자바 디자인 패턴 14 – Builder 15. 자바 디자인 패턴 15 – Mediator 16. 자바 디자인 패턴 16 – Visitor 출처 : http://iilii.egloos.com 글 내비게이션 Previo ... more

Commented by 용식 at 2009/02/18 09:31
아침에 출근해서 멍하니 포스트 보러 들어왔다가
두뇌 자극 받고 갑니다 ^^
말씀하신 확장을 한번 코드로 구현해봐야겠어요.

이 패턴은 정말 유용하게 사용 할 수 있는 (그런 패턴 아닌게 어디 있겠습니다만..--ㅋ)
패턴인것 같습니다.

좋은 글 감사합니다~!
Commented by 삼실청년 at 2009/02/19 17:21
이미 다 아시는 거면서 겸손하시군요^^
아~ 요즘 무기력증에 빠져서 큰일입니다. 무기력증 탈출할 수 있는 좋은 방법 있으면 좀 알켜주세요.
Commented by 용식 at 2009/02/20 00:56
삼실청년님! 저는 모르는 것은 모른다고 말씀드립니다 ^^
요 패턴은요~ 헤드퍼스트 메인에 안 나와있어서 제가 제대로 보지 못 한 패턴입니다 ^^
옛날에 봤던 일본 개발자분이 쓰신 그 패턴 책은... 음.. 정말 기억이 하나도 안나구요 -_-

저는 정말로 이 포스트를 써주셔서 감사해하고 있습니다. ㅎㅎㅎ

저도 한동안 좀 무기력해져서 루비를 한번 공부해 볼까 하고 루비책을 사서 집에서 보고
일본어도 공부해보고 회사 업무 시간 이후에는 자바 병렬 프로그래밍 (뭔지 아시죠? ^^
읽고 계시다는 그책..)을 읽고 있었는데요..

자바 병렬 프로그래밍 책을 읽다가 정신이 번쩍 들어서 무기력증이 싹 달아났습니다 ㅎㅎ

조금 공부했다고 자바에 대해서 너무 자신감을 가졌던 것 같아서요..
그래서 다른거 다 제껴두고 저 책 먼저 보고있습니다..^^

아무튼 청년님의 패턴에 대한 포스트는 정말 팍팍 와 닿습니다.
또 부탁드리겠습니다. ㅎㅎ
Commented by 삼실청년 at 2009/02/23 00:21
아니 벌써 헤드퍼스트 디자인 패턴을 다 봤다는 말인가요? 정말 열심히 하시는군요.
자바 병렬 프로그래밍.... 이눔 책은 봐도 봐도 읽히지가 않네요. 번역이 이상한 건 아닌 거 같은데.. 당췌 왜 눈에 안 들어오는 지 모르겠습니다.
첨에 디자인 패턴 쓰기 시작할 때는 한주에 하나씩만 올리자라고 생각했는데, 대략 1달에 1개 정도 썼더군요.-_-; 한 1년 반 쯤 지나면 대략 다 정리될 듯 합니다.-_-;
Commented by 용식 at 2009/02/23 11:03
저도 그 책 읽으면서
분명 번역이 이상한건 아닌데 왜 이렇게 이해가 어렵지 하고 있는데요..
그냥 실력탓이려니 하고.. 꾸역꾸역 읽고 있습니다.
그러다보니 한장 읽는 속도가 너무 더디네요..ㅎㅎ

헤드퍼스트는.. 그냥 쭉 읽었어요..문제는..읽을땐 이해가 되는데
막상 책 덮으면 "응??" 요상태라 -_-;;

참~ 1년반 기다리겠습니다. ㅎㅎㅎ
Commented by 삼실청년 at 2009/03/02 00:49
ㅎㅎ 나만 그런 거 아니라니 참 다행스럽습니다. 고맙습니다.-_-;

:         :

:

비공개 덧글

◀ 이전 페이지          다음 페이지 ▶