중재자 패턴
여러 객체들이 소통하는 방법을 캡슐화하는 패턴
- 여러 컴포넌트간의 결합도를 중재자를 통해 낮출 수 있다.
- 한 예로 비행기들은 관제탑이라는 Mediator 를 통해 서로 소통하는데, 이를 떠올리면서 학습하여 보자.
중재자 패턴 적용 전
호텔과 호텔의 여러 서비스들에 대한 코드이다.
먼저 호텔을 살펴보자.
public class Hotel {
public static void main(String[] args) {
Guest guest = new Guest();
guest.getTowel(3);
guest.dinner();
Restaurant restaurant = new Restaurant();
restaurant.clean();
}
}
main 에서 guest (손님) 가 타월을 달라고 요청하고, 식사를 한다.
그리고 restaurant (식당) 에 청소를 요청한다.
public class CleaningService {
public void clean(Gym gym) {
System.out.println("clean " + gym);
}
public void getTowel(Guest guest, int numberOfTowel) {
System.out.println(numberOfTowel + " towels to " + guest);
}
public void clean(Restaurant restaurant) {
System.out.println("clean " + restaurant);
}
}
public class Guest {
private Restaurant restaurant = new Restaurant();
private CleaningService cleaningService = new CleaningService();
public void dinner() {
restaurant.dinner(this);
}
public void getTowel(int numberOfTowel) {
cleaningService.getTowel(this, numberOfTowel);
}
}
Guest 는 restaurant 와 cleaningService 를 Aggregate(포함) 하고있다.
public class Gym {
private CleaningService cleaningService;
public void clean() {
cleaningService.clean(this);
}
}
Gym 은 cleaningService 를 Aggregate(포함) 하고있다.
public class Restaurant {
private CleaningService cleaningService = new CleaningService();
public void dinner(Guest guest) {
System.out.println("dinner " + guest);
}
public void clean() {
cleaningService.clean(this);
}
}
Restaurant 은 cleaningService 를 Aggregate(포함) 하고있다.
문제점
- 각 클래스를 보면 의존관계가 얽혀있는 것을 볼 수 있다.
- 이렇게 다양한 클래스들이 엮이게 되는 상황에서 중재자 패턴을 적용해보자.
Guest 클래스를 살펴보자. (Collegue A)
@Getter
@Setter
public class Guest {
private int id;
private FrontDesk frontDesk = new FrontDesk();
public void getTowels(int numberOfTowels) {
this.frontDesk.getTowels(this, numberOfTowels);
}
private void dinner(LocalDateTime dateTime) {
this.frontDesk.dinner(this, dateTime);
}
}
Guest 는 FrontDesk 를 가지고 있는데, Cleaning , Restaurant 등 모든 서비스를 FrontDesk(중재자) 를 통해 요청하고 있다.
FrontDesk (Mediator)
public class FrontDesk {
private CleaningService cleaningService = new CleaningService();
private Restaurant restaurant = new Restaurant();
public void getTowels(Guest guest, int numberOfTowels) {
cleaningService.getTowels(guest.getId(), numberOfTowels);
}
public String getRoomNumberFor(int guestId) {
return guestId + "의 room number";
}
public void dinner(Guest guest, LocalDateTime dateTime) {
restaurant.dinner(guest.getId(), dateTime);
}
public void clean() {
cleaningService.clean();
}
}
FrontDesk 는 중재자로써 모든 서비스들을 알고 있어도 된다. Guest 가 요청한 서비스를 각 서비스들에게 전달한다.
CleaningService (Collegue B)
public class CleaningService {
private FrontDesk frontDesk = new FrontDesk();
public void getTowels(int guestId, int numberOfTowels) {
String roomNumber = this.frontDesk.getRoomNumberFor(guestId);
System.out.println(roomNumber + "에 " + numberOfTowels + " 개의 towels 들을 배달했습니다.");
}
public void clean() {
System.out.println("청소하기");
}
}
Restaurant (CollegueC)
public class Restaurant {
private FrontDesk frontDesk = new FrontDesk();
public void cleanRestaurant() {
frontDesk.clean();
}
public void dinner(int id, LocalDateTime dateTime) {
System.out.println(id + "번 Guest 의 저녁식사를 " + dateTime + " 에 준비해두겠습니다.");
}
}
Restaurant 역시 clean 서비스가 필요하다면 직접 CleanService 에게 요청하는것이 아니라 FrontDesk 를 통해 요청하고 있다.
장점과 단점
장점
- 컴포넌트 코드를 변경하지 않고 새로운 중재자를 만들어 사용할 수 있다.
- 각각의 컴포넌트 코드를 보다 간결하게 유지할 수 있다.
단점
- 중재자 역할을 하는 클래스의 복잡도화 결합도가 증가한다.
- 의존성이 한 곳으로 몰린다.
실무에선 어떻게 쓰이나?
자바
- ExcutorService
- Executor
스프링
- MVC 의 DispatcherService
- 디스패처 서블릿은 다양한 핸들러와 어댑터들을 가지고 이들을 이어준다.
참고
'디자인 패턴' 카테고리의 다른 글
상태 패턴 (State Pattern) (0) | 2022.08.13 |
---|---|
메멘토 패턴 (Memento Pattern) (0) | 2022.08.12 |
이터레이터 패턴 (Iterator Pattern) (0) | 2022.08.04 |
인터프리터 패턴 (Interpreter Pattern) (0) | 2022.08.03 |
커맨드 패턴 (Command Pattern) (0) | 2022.08.02 |