2022. 1. 24. 23:58ㆍETC/Design Patterns
Object Behavioral Pattern
Mediator Pattern
----------------- INDEX -----------------
Mediator Pattern ?
Structure
Case Study
Sample Code: Java
관련 패턴
----------------------------------------------
Define an object that encapsulates how a set of objects interact.
Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
- GoF Design Patterns
중재자 패턴은 모든 클래스간의 상호작용을 캡슐화하여 하나의 클래스에 위임하여 처리하는 패턴입니다.
참고로, 위의 GoF의 디자인 패턴 소개를 해석해보자면 다음과 같습니다.
객체들의 집합이 상호 작용하는 방식을 함축해놓은(캡슐화하는) 객체를 정의합니다.
중재자는 객체가 명시적으로 서로를 참조하지 못하도록 함으로써 느슨하게 결합하도록 하며,
사용자가 객체 간 상호 작용을 독립적으로 변경할 수 있습니다.
복잡한 구조
객체지향에서는 모듈화를 통해 하나의 로직을 작은 단위의 객체로 분산시킵니다.
객체를 분할해서 해당 로직을 재사용하기 위함입니다.
하지만, 하나의 전체적인 로직을 만들기 위해서는 각 객체마다의 의존 관계가 생기기 마련인데요.
이 때 분리된 객체의 의존 관계는 구조적으로 복잡하게 연결되며 결합도가 증가할 수 있습니다.
중재자는 이렇게 객체 간의 복잡한 상호 관계를 중재하며 복잡하게 연결된 것들은 재구성해줍니다.
쉽게 생각하면 서로 의존적인 M:N 의 관계를 가진 객체를 느슨한 1:1 관계로 변경할 수 있습니다.
실생활에서의 중재자
중재자 패턴은 실생활에서의 중재자와 같은 역할을 합니다.
예를 들어 토론에서 사회자는 여러 패널의 발언권을 제어하고 이를 정리하는 역할을 합니다.
혹은, 각종 모임에서 총무는 각 회원에게 회식 비용을 받아 결제를 대행합니다. 회원이 일일이 계산하는 것은 복잡하기 때문이죠.
위의 두 예시에서 각각 사회자와 총무가 바로 중재자 역할을 합니다.
이렇게 이해 관계자가 많은 경우 이를 정리하는 중개인이 있으면 일을 보다 편리하게 처리할 수 있습니다.
중재자 패턴이 유용한 경우
✔️ 객체들 사이에 너무 많은 관계가 얽혀있을때
✔️ 객체들 사이의 상호작용 관계가 복잡할때
Structure
Mediator
Colleague 클래스들과 통신하기 위한 Interface를 정의합니다.
ConcreteMediator
구현된 Mediator는 Colleague들을 접근할 수 있어야 하며 Colleague들을 관리합니다.
접근할 수 있다는 것은 Mediator가 Colleague를 알고 있어야 한다는 의미로, 속성으로 갖거나 전달받을 수 있습니다.
Colleague 객체들의 상호작용을 조정하기 위한 협력 동작cooperative behavior을 구현합니다.
Colleague classes
각 Colleague 클래스는 Mediator 객체에 접근할 수 있습니다.
접근할 수 있다는 것은 Colleague가 Mediator를 알고 있어야 한다는 의미로, 속성으로 갖거나 전달받을 수 있습니다.
다른 Colleague와 상호작용을 할 때마다 Mediator를 통해 상호작용을 합니다.
Case Study
폰트를 지정하려고 팝업창을 띄웠다고 생각해보세요.
아래의 그림과 같이 textfield, checkboxe, button 등과 같은 요소들로 구성되겠죠?
이 때, 각각의 요소들에는 복잡한 상호작용을 볼 수 있습니다.
예를 들어 Family에 해당하는 textfield에 원하는 폰트명 "new"을 입력하면
List box 에서 연관된 폰트인 "new century schoolbook"가 선택됩니다.
또, 어떤 폰트에서는 Demi Bold를 지원하지 않지만 다른 폰트에서는 지원할 수도 있어요.
각각의 요소가 복잡하게 얽혀있는게 느껴지시나요?
여기서, textfield, checkboxe, button 등의 구성요소component가 바로 Colleague 입니다.
그리고 Mediator를 통해 이 Colleague들을 중재해줄 수 있습니다.
이제 코드로 확인해볼게요.
Sample Code: Java
유저의 프로필을 만들고 편집할 수 있는 Dialog를 제작한다고 해봅시다.
text field, checkboxe, button 등과 같은 다양한 폼 컨트롤로 구성됩니다.
위의 그림과 같이 Profile, Login은 동일한 구성요소를 가집니다.
이 둘을 Dialog 클래스 하나로 만들고, checkbox를 통해 전환할 수 있게 하겠습니다.
Mediator
public interface Mediator {
void notify(Component sender, String event);
}
ConcreteMediator
public class Dialog implements Mediator {
public String title;
public Checkbox isJoinForm;
public Textbox username;
public Textbox password;
public Button ok;
public Button cancel;
public Checkbox remeberMe;
public Dialog() {
super();
title = "Login";
isJoinForm = new Checkbox(this);
username = new Textbox(this);
password = new Textbox(this);
ok = new Button(this);
cancel = new Button(this);
remeberMe = new Checkbox(this);
}
public void printCurrentStatus() {
System.out.println("Title: " + title);
System.out.println("isJoinForm: " + isJoinForm.checked());
System.out.println("remeberMe: " + remeberMe.checked());
}
@Override
public void notify(Component sender, String event) {
// OK 버튼을 눌렀을 경우
if(sender.equals(ok) && "click".equals(event)) {
if(isJoinForm.checked()) {
System.out.println("Validate - user info \n Sign up");
} else {
System.out.println("Login");
}
}
// Sign Up 폼을 부르는 버튼을 눌렀을 경우
else if(sender.equals(isJoinForm) && "check".equals(event)) {
if(isJoinForm.checked()) {
title = "User Join Form";
System.out.println("show colleague components");
} else {
title = "Login";
System.out.println("hide colleague components");
}
}
// 정보 저장 버튼을 눌렀을 경우
else if(sender.equals(remeberMe) && "check".equals(event)) {
if(remeberMe.checked()) {
System.out.println("set ID in cookie");
} else {
System.out.println("remove ID from cookie");
}
}
}
}
Colleague
public class Component {
protected Mediator dialog;
public Component(Mediator dialog) {
super();
this.dialog = dialog;
}
public void click() {
dialog.notify(this, "click");
}
public void keypress() {
dialog.notify(this, "keypress");
}
}
Colleague Classes - detail components
public class Button extends Component{
public Button(Mediator dialog) {
super(dialog);
}
}
public class Textbox extends Component {
public Textbox(Mediator dialog) {
super(dialog);
}
}
public class Checkbox extends Component {
private boolean checked;
public Checkbox(Mediator dialog) {
super(dialog);
checked = false;
}
public boolean checked() {
return checked;
}
@Override
public void click() {
checked = !checked;
dialog.notify(this, "check");
super.click();
}
}
관련 패턴
C- Creational Patterns | S - Structural Patterns | B - Behavioral Patterns
퍼사드 패턴은 더 편리한 인터페이스를 제공하는 추상화 작업입니다.
통신을 위해 높은 레벨의 인터페이스를 만든다는 점에서 중재자 패턴과 비슷하게 볼 수 있습니다.
하지만, 중재자 패턴은 양방향 통신이고 퍼사드는 단방향 통신입니다.
중재자가 Colleague 의 요청을 감지할 경우 감시자Observer 패턴을 같이 활용할 수 있습니다.
감시자 패턴과 중재자 패턴의 경계가 모호할 수 있는데요.
둘의 차이는 목적이 다르다는 것입니다.
감시자 패턴은 상태만 통보하고 중재자 패턴은 역할 조정을 목적으로 통보합니다.
그럼 지금까지 Mediator Pattern에 대해 알아보았습니다.
오타나 잘못된 내용이 있다면 댓글로 남겨주세요!
감사합니다 ☺️
참고
https://refactoring.guru/design-patterns/mediator
'ETC > Design Patterns' 카테고리의 다른 글
Design Pattern, Composite (0) | 2022.02.01 |
---|---|
Design Pattern, Singleton (0) | 2022.01.26 |
Design Pattern, Adapter (0) | 2022.01.23 |
Design Pattern, Observer (0) | 2022.01.21 |
Design Pattern, Proxy (0) | 2022.01.12 |
Backend Software Engineer
𝐒𝐮𝐧 · 𝙂𝙮𝙚𝙤𝙣𝙜𝙨𝙪𝙣 𝙋𝙖𝙧𝙠