2011년 5월 23일 월요일

The Mediator Pattern

17. The Mediator Pattern
어떤 프로그램이 여러 개의 클래스로 만들어져 있을 때 로직과 계산은 이러한 클래스로부터 논리적으로 나뉘어 진다. 그러나 이러한 고립적인 클래스들이 증가함에 따라 이러한 클래스들의 통신 문제가 보다 복잡해졌다. 다른 클래스의 메소드들에 대하여 아는 것이 필요한 클래스가 더 많아지고 클래스들의 구조는 더 얽혀 복잡해 진다. 이것이 프로그램을 읽는 것과 유지를 어렵게 한다. 게다가 프로그램을 변경하는 것이 어려운데 왜냐면 어떤 변화가 여러 개의 다른 클래스들에서 코드에 영향을 줄 지도 모르기 때문이다. Mediator 패턴은 이러한 클래스들 사이의 느슨한 커플링을 진행하여 이러한 문제를 해결할 수 있는 방법을 소개한다. Mediator는 다른 클래스들의 메소드들에 대한 정보를 설명한 오직 하나의 클래스의 이용하여 이 문제를 해결할 수 있다. 클래스들은 변경되었을 때 mediator에게 정보를 준고 Mediator는 정보를 필요로 하는 다른 클래스들에게 정보를 전달해 준다.
구조
*


역할
  • Mediator – Colleague 역할과 통신을 해서 조정을 하기 위한 인터페이스(API)를 정하는 역할을 한다.
  • ConcreteMediator – Mediator 역할의 인터페이스(API)를 구현하여 실제의 조정을 수행 하는 역할을 한다.
  • Colleague – Mediator 역할과 통신을 할 인터페이스(API)를 정합니다.
  • Concretecolleague – Colleague 역할의 인터페이스(API)를 구현합니다.


의도
다수의 객체를 조정해야 하는 경우 Mediator 패턴을 사용합니다.

적용시기
  • 어떤 객체들의 집합이 잘 정의되었지만, 복잡한 방법으로 통신할 때.
  • 어떤 객체를 재사용하는 것이 그것이 많은 다른 객체들과 관련이 있고 통신을 하기 때문에 어려울 때.
  • 몇몇의 클래스들 사이에 분산되어진 하나의 행위가 많은 subclassing하는 작업 없이 customize되어져야 할 때.


결론
  • Mediator 는 한 개의 클래스에서 일어나는 액션이 다른 상태에 반영되어야 할 경우 클래스들이 복잡해지는 것을 막는다.
  • Mediator 는 프로그램의 작동을 쉽게 한다. 많이 변경할 경우 단지 Mediator를 변경하거나 서브클래스로 분류한다. 그리고 나머지 프로그램은 변경하지 않은 상태로 둔다.
  • 새로운 컨트롤이나 다른 클래스들이 Mediator를 제외한 어떤 것도 변경하지 않고 추가할 수 있다.
  • Mediator 는 객체와 나머지 사용자 인터페이스에 있는 메소드에 대해서 모두 알고 있어야 하는 각각의 command 객체의 문제를 해결한다.
  • 가끔 Mediator 는 프로그램에 대해 너무 많은 지식을 갖는 ‘god 클래스’ 가 될수 있는데, 이것은 Mediator를 변경하고 유지하게 어렵게 만든다. 개별적 클래스에 좀더 많은 기능을 추가하고, Mediator에는 기능을 줄여서 이러한 상황을 개선할 수 있다. 각각의 객체는 자신의 업무를 샐행한다. 그리고 Mediator 는 객체들 간의 상호 작용을 관리한다.
  • 각각의 Mediator는 호출하기 위해서 각각의 colleague 의 메소드를 가지는데, 이것은 Colleague마다 가지고 있는 메소드가 유용한지를 아는 맞춤형 쓰기 클래스이다. 이것은 다른 프로젝트에서 사용한 Mediator 코드를 다시 하용하는 것을 어렵게 한다. 그러나 대부분의 Mediator는 아주 간단하며, 이 코드를 사용하는 것이 다른 방법으로 복잡한 객체 상호 작용을 관리하는 것보다 훨씬 쉽다.
    구현상의 문제
    Mediator는 가장 일반적인 패턴이지만, 비주얼 인터페이스 프로그램에서 매우 폭넓게 사용된다. 다중 객체들 간의 복잡한 상호 의사 소통을 해결해야 하는 문제에 직면할 때마다 Mediator를 사용할 수 있다.


    예제소스

    이 프로그램은 왼쪽에 (50free.txt)파일에 등록된 모든 아이들을 표시하고, 클럽 리스트로 콤보 박스를 체운다. 그런 다음 사용자가 클럽을 선택하면 우측리스트에는 클럽에 소속된 아이들만 표시한다.
    예제 소스
    public interface Mediator {
    public abstract void createColleagues();
    public abstract void colleagueChanged(Colleague colleague);
    }
    public interface Colleague {
    public abstract void setMediator(Mediator mediator);
    public abstract void setColleagueEnabled(boolean enabled);
    }
    import java.awt.Button;
    public class ColleagueButton extends Button implements Colleague {
    private Mediator mediator;
    public ColleagueButton(String caption) {
    super(caption);
    }
    public void setMediator(Mediator mediator) {
    this.mediator = mediator;
    }
    public void setColleagueEnabled(boolean enabled) {
    setEnabled(enabled);
    }
    }
    import java.awt.Checkbox;
    import java.awt.CheckboxGroup;
    import java.awt.event.ItemListener;
    import java.awt.event.ItemEvent;
    public class ColleagueCheckbox extends Checkbox implements ItemListener, Colleague {
    private Mediator mediator;
    public ColleagueCheckbox(String caption, CheckboxGroup group, boolean state) {
    super(caption, group, state);
    }
    public void setMediator(Mediator mediator) {
    this.mediator = mediator;
    }
    public void setColleagueEnabled(boolean enabled) {
    setEnabled(enabled);
    }
    public void itemStateChanged(ItemEvent e) {
    mediator.colleagueChanged(this);
    }
    }
    import java.awt.TextField;
    import java.awt.Color;
    import java.awt.event.TextListener;
    import java.awt.event.TextEvent;
    public class ColleagueTextField extends TextField implements TextListener, Colleague {
    private Mediator mediator;
    public ColleagueTextField(String text, int columns) {
    super(text, columns);
    }
    public void setMediator(Mediator mediator) {
    this.mediator = mediator;
    }
    public void setColleagueEnabled(boolean enabled) {
    setEnabled(enabled);
    setBackground(enabled ? Color.white : Color.lightGray);
    }
    public void textValueChanged(TextEvent e) {
    mediator.colleagueChanged(this);
    }
    }
    import java.awt.Frame;
    import java.awt.Label;
    import java.awt.Color;
    import java.awt.CheckboxGroup;
    import java.awt.GridLayout;
    import java.awt.event.ActionListener;
    import java.awt.event.ActionEvent;
    public class LoginFrame extends Frame implements ActionListener, Mediator {
    private ColleagueCheckbox checkGuest;
    private ColleagueCheckbox checkLogin;
    private ColleagueTextField textUser;
    private ColleagueTextField textPass;
    private ColleagueButton buttonOk;
    private ColleagueButton buttonCancel;
    public LoginFrame(String title) {
    super(title);
    setBackground(Color.lightGray);
    setLayout(new GridLayout(4, 2));
    createColleagues();
    add(checkGuest);
    add(checkLogin);
    add(new Label("Username:"));
    add(textUser);
    add(new Label("Password:"));
    add(textPass);
    add(buttonOk);
    add(buttonCancel);
    colleagueChanged(checkGuest);
    pack();
    show();
    }
    public void createColleagues() {
    CheckboxGroup g = new CheckboxGroup();
    checkGuest = new ColleagueCheckbox("Guest", g, true);
    checkLogin = new ColleagueCheckbox("Login", g, false);
    textUser = new ColleagueTextField("", 10);
    textPass = new ColleagueTextField("", 10);
    textPass.setEchoChar('*');
    buttonOk = new ColleagueButton("OK");
    buttonCancel = new ColleagueButton("Cancel");
    checkGuest.setMediator(this);
    checkLogin.setMediator(this);
    textUser.setMediator(this);
    textPass.setMediator(this);
    buttonOk.setMediator(this);
    buttonCancel.setMediator(this);
    checkGuest.addItemListener(checkGuest);
    checkLogin.addItemListener(checkLogin);
    textUser.addTextListener(textUser);
    textPass.addTextListener(textPass);
    buttonOk.addActionListener(this);
    buttonCancel.addActionListener(this);
    }
    public void colleagueChanged(Colleague c) {
    if (c == checkGuest || c == checkLogin) {
    if (checkGuest.getState()) {
    textUser.setColleagueEnabled(false);
    textPass.setColleagueEnabled(false);
    buttonOk.setColleagueEnabled(true);
    } else {
    textUser.setColleagueEnabled(true);
    userpassChanged();
    }
    } else if (c == textUser || c == textPass) {
    userpassChanged();
    } else {
    System.out.println("colleagueChanged:unknown colleague = " + c);
    }
    }
    private void userpassChanged() {
    if (textUser.getText().length() > 0) {
    textPass.setColleagueEnabled(true);
    if (textPass.getText().length() > 0) {
    buttonOk.setColleagueEnabled(true);
    } else {
    buttonOk.setColleagueEnabled(false);
    }
    } else {
    textPass.setColleagueEnabled(false);
    buttonOk.setColleagueEnabled(false);
    }
    }
    public void actionPerformed(ActionEvent e) {
    System.out.println("" + e);
    System.exit(0);
    }
    }
    public class Main {
    static public void main(String args[]) {
    new LoginFrame("Mediator 패턴 Demo");
    }
    }


    관련패턴
    • Façade Pattern – Mediator 패턴에서 Mediator 역할은 Colleague 역할의 중개자로서 주고 받기를 수행합니다. Façade 패턴에서는 Façade 역할이 일방적으로 다른 역할을 이용해서 높은 레벨의 인터페이스(API)를 만듭니다. Mediator가 양방향이지만, Façade 는 단 방향이라고 말할 수 있습니다.
    • Observer Pattern – Mediator 역할과 Colleague 역할의 통신은 Observer 패턴을 사용하여 수행되는 경우가 있습니다.

댓글 없음:

댓글 쓰기

ETL 솔루션 환경

ETL 솔루션 환경 하둡은 대용량 데이터를 값싸고 빠르게 분석할 수 있는 길을 만들어줬다. 통계분석 엔진인 “R”역시 하둡 못지 않게 관심을 받고 있다. 빅데이터 역시 데이터라는 점을 볼때 분산처리와 분석 그 이전에 데이터 품질 등 데이...