중재자 패턴
- 객체 지향 프로그래밍에서 객체 간의 상호작용을 간소화하고 캡슐화하는 데 사용되는 패턴
- 객체들이 서로 직접 통신하는 것을 피하고 중앙에 있는 중재자 객체를 통해 통신하게 함으로써 여러 컴포넌트 간의 결합도를 중재자를 통해 낮출 수 있음

주요 구성 요소
1. Mediator
- 중재자 역할을 수행하는 인터페이스를 정의
2. ConcreteMediator
- Mediator 인터페이스 구현체
- 객체들 간의 상호작용을 조정
3. Colleague
- Mediator와 상호작용하는 객체
- 일반적으로 Colleague 객체들은 Mediator 객체를 통해서만 서로 통신
4. ConcreteColleague
- Colleague 인터페이스 구현체
- 해당 객체들은 Mediator를 통해 다른 Colleague들과 통신
중재자 패턴 구현 예시
1. ChatMediator (Mediator)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface ChatMediator { | |
void sendMessage(String message, User user); | |
void addUser(User user); | |
} |
2. ChatMediatorImpl (ConcreteMediator)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ChatMediatorImpl implements ChatMediator { | |
private List<User> users; | |
public ChatMediatorImpl() { | |
this.users = new ArrayList<>(); | |
} | |
@Override | |
public void addUser(User user) { | |
this.users.add(user); | |
} | |
@Override | |
public void sendMessage(String message, User user) { | |
for (User u : this.users) { | |
// 메시지를 보낸 사용자를 제외한 모든 사용자에게 메시지를 전달 | |
if (u != user) { | |
u.receive(message); | |
} | |
} | |
} | |
} |
3. User (Colleague)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
abstract class User { | |
protected ChatMediator mediator; | |
protected String name; | |
public User(ChatMediator mediator, String name) { | |
this.mediator = mediator; | |
this.name = name; | |
} | |
public abstract void send(String message); | |
public abstract void receive(String message); | |
} |
4. UserImpl (ConcreteColleague)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class UserImpl extends User { | |
public UserImpl(ChatMediator mediator, String name) { | |
super(mediator, name); | |
} | |
@Override | |
public void send(String message) { | |
System.out.println(this.name + "가 보내는 메시지: " + message); | |
mediator.sendMessage(message, this); | |
} | |
@Override | |
public void receive(String message) { | |
System.out.println(this.name + "가 받은 메시지: " + message); | |
} | |
} |
5. 클라이언트 코드
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Client { | |
public static void main(String[] args) { | |
ChatMediator mediator = new ChatMediatorImpl(); | |
User chulsoo = new UserImpl(mediator, "철수"); | |
User hooni = new UserImpl(mediator, "훈이"); | |
User zzanggu = new UserImpl(mediator, "짱구"); | |
User maenggu = new UserImpl(mediator, "맹구"); | |
User yuri = new UserImpl(mediator, "유리"); | |
mediator.addUser(chulsoo); | |
mediator.addUser(hooni); | |
mediator.addUser(zzanggu); | |
mediator.addUser(maenggu); | |
mediator.addUser(yuri); | |
chulsoo.send("안녕하세요, 여러분!"); | |
} | |
} |

부연 설명
- ChatMediator가 중재자 역할을 하고, User 클래스가 Colleague 역할
- User 객체들은 ChatMediator를 통해서만 서로 통신하여 객체 간의 결합도를 줄이고 유지보수가 용이해짐
중재자 패턴 장단점
장점
- 객체들이 직접 서로 통신하지 않고 중재자를 통해 통신하므로, 객체 간의 결합도가 낮아짐
- 객체 간의 복잡한 상호작용을 중앙에서 관리하므로, 각 객체는 자신의 역할에만 집중할 수 있음 (SOLID의 SRP 원칙)
- 새로운 객체를 추가할 때 기존 객체를 변경할 필요가 없으며 중재자를 통해 새로운 객체를 추가하면 되므로 시스템의 확장성이 높아짐 (SOLID의 OCP 원칙)
단점
- 중재자 역할을 하는 클래스의 복잡도와 결합도가 높아짐
- 중재자가 시스템의 또 다른 단일 실패 지점(single point of failure)이 될 수 있음
- 객체들이 직접 통신하지 않고 중재자를 통해 통신하기 때문에 디버깅이 어려울 수 있음
- 중재자를 통해 발생하는 모든 상호작용을 추적해야 함
실무에서 쓰이는 중재자 패턴
1. 자바의 ExecutorService
- 자바의 java.util.concurrent 패키지에서 제공하는 인터페이스로, 비동기 작업을 관리하고 실행하는 메커니즘을 제공
- ExecutorService는 스레드 풀을 사용하여 작업을 처리하며, 이를 통해 애플리케이션의 쓰레드 관리를 단순화하고 효율성을 높임
- 중재자 패턴의 관점에서 살펴보면, ExecutorService가 중재자 역할을 하고, 작업(Task)들이 Colleague 역할을 수행한다고 볼 수 있음
- ExecutorService는 중재자로서 역할을 수행하며, 작업(Task)들의 실행을 관리
- Task들이 서로 직접 쓰레드 관리를 하지 않고, ExecutorService를 통해 간접적으로 스레드를 사용
- Runnable 또는 Callable 인터페이스를 구현하는 작업들이 Colleague 역할
2. 스프링 DispatcherServlet
- Spring Framework의 DispatcherServlet은 웹 애플리케이션에서 클라이언트 요청을 처리하고 적절한 컨트롤러로 요청을 라우팅 하는 역할
- 중재자 패턴의 관점에서 볼 때, DispatcherServlet은 중재자 역할을 수행하며, 여러 컨트롤러들이 Colleague 역할
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { | |
HttpServletRequest processedRequest = request; | |
HandlerExecutionChain mappedHandler = null; | |
ModelAndView mv = null; | |
Exception dispatchException = null; | |
try { | |
processedRequest = checkMultipart(request); | |
// 핸들러 매핑 | |
mappedHandler = getHandler(processedRequest); | |
if (mappedHandler == null) { | |
noHandlerFound(processedRequest, response); | |
return; | |
} | |
// 핸들러 어댑터 가져오기 | |
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); | |
// 실제 핸들러 호출 | |
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); | |
// 뷰 이름 해석 | |
if (mv != null && !mv.wasCleared()) { | |
render(mv, processedRequest, response); | |
} else { | |
response.flushBuffer(); | |
} | |
} catch (Exception ex) { | |
dispatchException = ex; | |
} catch (Error err) { | |
dispatchException = new NestedServletException("Handler dispatch failed", err); | |
} finally { | |
if (dispatchException != null) { | |
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); | |
} else { | |
processDispatchResult(processedRequest, response, mappedHandler, mv, null); | |
} | |
} | |
} |
부연 설명
- DispatcherServlet은 중재자로서 클라이언트 요청을 받아 여러 구성 요소들 간의 상호작용을 조정하며 doDispatch 메서드는 이러한 역할을 잘 보여줌
- 다양한 컴포넌트가 Colleague 역할
- HandlerMapping: 요청 URL을 기반으로 적절한 핸들러를 찾는 역할을 수행하며 여러 종류의 HandlerMapping이 존재할 수 있고 각각의 역할은 서로 독립적
- HandlerAdapter: 찾은 핸들러를 실행할 수 있는 어댑터를 제공하며 핸들러의 타입에 따라 적절한 어댑터가 선택됨
- ViewResolver: 핸들러가 반환한 뷰 이름을 실제 View 객체로 변환하며 여러 ViewResolver가 존재할 수 있고 각각의 역할은 서로 독립적
참고
코딩으로 학습하는 GoF의 디자인 패턴 - 백기선 강사님
반응형
'Design Pattern' 카테고리의 다른 글
[디자인 패턴] 이터레이터 패턴 (Iterator Pattern) (0) | 2024.06.30 |
---|---|
[디자인 패턴] 인터프리터 패턴 (Interpreter Pattern) (0) | 2024.06.30 |
[디자인 패턴] 책임 연쇄 패턴 (Chain-of-Responsibility Pattern) (0) | 2024.06.29 |
[디자인 패턴] 프록시 패턴 (Proxy Pattern) (0) | 2024.06.29 |
[디자인 패턴] 플라이웨이트 패턴 (Flyweight Pattern) (0) | 2024.06.29 |