개요
한 그룹을 이루는 여러 회원들이 서로 업무를 파악하며 관여하거나 어떤 일을 처리할 때 각자 의견을 주장한다면 해당 그룹은 목적을 이뤄나가기에 많은 비용이 소모될 것이다. 이런 상황을 해결하기 위해 조정자, 중개인을 두고 의사결정과 상황판단을 중개인을 통해서만 처리함으로 그룹의 효율을 높일 수 있다.
위와 같은 경우를 프로그래밍에 적용한 패턴이 바로 Mediator(중개인, 조정자) 패턴이다.
역할
Mediator 역할
Colleague 역할과 통신을 해서 조정하기 위한 인터페이스를 정의한다. 예제에서는 Mediator 인터페이스.
ConcreteMediator 역할
Mediator 역할이 정의한 인터페이스를 구현해서 실제 조정자 역할을 한다. 예제에서는 LoginFrame 클래스.
Colleague 역할
Mediator 역할과 통신을 실행할 인터페이스를 정의한다. 예제에서는 Colleague 인터페이스.
ConcreteColleague 역할
Colleague 역할이 정의한 인터페이스를 구현한다. 그룹의 회원과 같은 역할. 예제에서는 ColleagueButton, ColleagueTextField, ColleagueCheckbox 클래스.
이득 및 주의사항
객체지향 프로그래밍에선 모듈화를 통해 업무를 분산시켜 처리하는 경우를 쉽게 볼 수 있다. 그런데 Mediator 패턴은 문제처리를 한 모듈로 집중시키는 패턴처럼 보인다. 하지만 자세히 보면 기능은 각 모듈로 분산시키고, 이를 가지고 업무를 처리하는 로직만 집중시킨다는 것을 알 수 있다. 이렇게 부분적으로 분산시켜야 할 기능과 집중시켜야 하는 작업을 효과적으로 분리 하면 로직이 수정되거나 시스템의 문제가 발생했을 때 더 효과적으로 대처할 수 있는 이점이 있다.
ConcreteColleague 역할은 화면(애플리케이션) 구성에서 자유로운 부분이기 때문에 재사용이 가능해서 새로운 화면이나 구성을 짤 때 사용할 수 있지만, ConcreteMediator는 화면(구성)과 종속적이기 때문에 애플리케이션에 종속적이다. 때문에 새로운 화면(구성)을 작성하기 위해서 ConcreteMediator의 재사용은 어렵고 새로운 ConcreteMediator를 구성하는게 오히려 비용이 저렴할 수 있다.
예제 코드
//Mediator 역할
package mediator;
public interface Mediator {
public abstract void createColleagues();
public abstract void colleagueChanged();
}
//ConcreteMediator 역할
package mediator;
import java.awt.CheckboxGroup;
import java.awt.Color;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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());
createColleagues();
add(checkGuest);
add(checkLogin);
add(new Label("Username : "));
add(textUser);
add(new Label("Password : "));
add(textPass);
add(textPass);
add(buttonOK);
add(buttonCancel);
colleagueChanged();
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);
}
//Colleague에서 통지로 Colleague의 유/무효를 판단한다.
public void colleagueChanged() {
if(checkGuest.getState()) {
textUser.setColleagueEnabled(false);
textPass.setColleagueEnabled(false);
buttonOK.setColleagueEnabled(true);
} else {
textUser.setColleagueEnabled(true);
userpassChanged();
}
}
//textUser나 textPass의 변경이 발생시 각 Colleague의 유/무효를 판단한다.
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.toString());
System.exit(0);
}
}
//Colleague 역할
package mediator;
public interface Colleague {
public abstract void setMediator(Mediator mediator);
public abstract void setColleagueEnabled(boolean enabled);
}
//ConcreteColleague 역할1
package mediator;
import java.awt.Color;
import java.awt.TextField;
import java.awt.event.TextEvent;
import java.awt.event.TextListener;
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();
}
}
//ConcreteColleague 역할2
package mediator;
import java.awt.Checkbox;
import java.awt.CheckboxGroup;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
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();
}
}
//ConcreteColleague 역할3
package mediator;
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);
}
}
//Tester
package mediator;
public class MediatorTester {
public static void main(String[] args) {
// TODO Auto-generated method stub
new LoginFrame("Mediator Sample");
}
}
'디자인 패턴' 카테고리의 다른 글
18. Memento 패턴 (0) | 2020.12.30 |
---|---|
17. Observer 패턴 (0) | 2020.12.29 |
15. Facade 패턴 (0) | 2020.12.26 |
14. Chain of Responsibility 패턴 (0) | 2020.12.22 |
13. Visitor 패턴 (0) | 2020.12.17 |