미디에이터 패턴
서로 영향을 주는 객체들이 직접 얽히지 않도록 상호작용 규칙을 중재 객체에 모으는 행위 패턴.
· 마지막 업데이트: 2026-10-25 · 6 min read
개요
입력 완료 여부와 확인 체크박스에 따라 제출 버튼이 켜진다고 하자. 체크박스가 버튼과 다른 입력 칸을 직접 참조하기 시작하면, 화면을 바꿀 때 서로의 코드를 함께 고치게 된다.
미디에이터(Mediator), 즉 중재자는 객체들 사이의 상호작용을 조정한다. 각 요소는 자기 변화만 알리고, 다른 요소를 어떻게 바꿀지는 중재자가 정한다.
UML
Toggle은 IFormMediator에 변화를 알린다. FormMediator가 두 조건을 모아 SubmitButton.Enabled를 정하므로 Toggle은 버튼을 직접 참조하지 않는다.
역사
GoF는 1994년 Design Patterns에서 Mediator를 행위 패턴으로 정리했다. 여러 객체 사이의 상호작용을 별도 객체에 캡슐화하는 구조다.1
왜 사용하는가?
화면 요소는 다른 요소의 구체적인 타입과 조정 규칙을 몰라도 된다. 제출 조건을 바꿀 때 중재자의 규칙을 확인하면 된다.
중재자가 화면 밖의 모든 업무까지 맡으면 큰 관리 객체가 된다. 이 예제는 폼 하나의 상태 조정에만 범위를 두며 서버의 입력 검증이나 권한 검사를 대신하지 않는다.
예제
입력 완료와 확인 체크가 모두 참이 되어야 버튼이 켜진다. Toggle은 실제 UI 대신 변경 알림만 보내는 대역이다.
using System;
using System.Collections.Generic;
using System.Linq;
var button = new SubmitButton();
IFormMediator mediator = new FormMediator(button);
new Toggle("details", mediator).Set(true);
Console.WriteLine(button.Enabled);
new Toggle("confirmed", mediator).Set(true);
Console.WriteLine(button.Enabled);
sealed class SubmitButton { public bool Enabled { get; set; } }
interface IFormMediator { bool Changed(string field, bool ready); }
// 여러 위젯 사이의 관계를 이 중재자 한곳에서 계산한다.
sealed class FormMediator(SubmitButton button) : IFormMediator
{
private bool details;
private bool confirmed;
public bool Changed(string field, bool ready)
{
switch (field)
{
case "details": details = ready; break;
case "confirmed": confirmed = ready; break;
default: return false;
}
button.Enabled = details && confirmed;
return true;
}
}
// 위젯은 값 변경만 알리고 다른 위젯을 직접 제어하지 않는다.
sealed class Toggle(string field, IFormMediator mediator)
{
public bool Set(bool ready) => mediator.Changed(field, ready);
}
False
True첫 조건만 참일 때는 버튼이 꺼져 있고, 두 번째 조건까지 들어온 뒤 켜진다.
범위 넓힌 예제
조건 하나를 다시 거짓으로 바꾸고, 모르는 필드 이름도 보내 본다.
using System;
using System.Collections.Generic;
using System.Linq;
var button = new SubmitButton();
IFormMediator mediator = new FormMediator(button);
mediator.Changed("details", true);
mediator.Changed("confirmed", true);
Console.WriteLine(button.Enabled);
mediator.Changed("details", false);
Console.WriteLine(button.Enabled);
Console.WriteLine(mediator.Changed("unknown", true));
Console.WriteLine(button.Enabled);
sealed class SubmitButton { public bool Enabled { get; set; } }
interface IFormMediator { bool Changed(string field, bool ready); }
// 여러 위젯 사이의 관계를 이 중재자 한곳에서 계산한다.
sealed class FormMediator(SubmitButton button) : IFormMediator
{
private bool details;
private bool confirmed;
public bool Changed(string field, bool ready)
{
switch (field)
{
case "details": details = ready; break;
case "confirmed": confirmed = ready; break;
default: return false;
}
button.Enabled = details && confirmed;
return true;
}
}
// 위젯은 값 변경만 알리고 다른 위젯을 직접 제어하지 않는다.
sealed class Toggle(string field, IFormMediator mediator)
{
public bool Set(bool ready) => mediator.Changed(field, ready);
}
True
False
False
False조건을 해제하면 버튼도 꺼진다. 알 수 없는 필드는 false를 반환하고 기존 상태를 바꾸지 않는다. Observer가 알림 관계를 분리한다면, 여기서는 알림을 받은 뒤 여러 요소를 어떻게 조정할지가 중심이다.
TypeScript 예제
각 Toggle은 값이 바뀌었다는 사실만 알리고, 버튼을 켜는 두 조건의 관계는 FormMediator가 맡는다. 한 토글이 다른 토글과 버튼의 내부 상태까지 알아야 하는 연결을 줄이려는 분리다.
class SubmitButton { enabled = false; }
interface IFormMediator { changed(field: string, value: boolean): boolean; }
// 여러 위젯 사이의 관계를 이 중재자 한곳에서 계산한다.
class FormMediator implements IFormMediator {
private details = false;
private confirmed = false;
constructor(private readonly button: SubmitButton) {}
changed(field: string, value: boolean): boolean {
if (field === "details") this.details = value;
else if (field === "confirmed") this.confirmed = value;
else return false;
this.button.enabled = this.details && this.confirmed;
return true;
}
}
// 위젯은 값 변경만 알리고 다른 위젯을 직접 제어하지 않는다.
class Toggle {
constructor(private readonly field: string, private readonly mediator: IFormMediator) {}
set(value: boolean): boolean { return this.mediator.changed(this.field, value); }
}
const button = new SubmitButton();
const mediator = new FormMediator(button);
new Toggle("details", mediator).set(true);
console.log("after details: " + button.enabled);
new Toggle("confirmed", mediator).set(true);
console.log("after confirmation: " + button.enabled);
console.log("unknown accepted: " + mediator.changed("unknown", false));
console.log("still enabled: " + button.enabled);after details: false
after confirmation: true
unknown accepted: false
still enabled: true알 수 없는 필드는 false로 거부하며 버튼 상태를 바꾸지 않는다. UI 조정 예제이므로 실제 제출에 필요한 서버 검증과 권한 검사는 별도다.
같이 보기
C# 예제는 각각 독립된 .NET 10 콘솔 프로그램이다.
TypeScript 예제는 ES2022 이상으로 컴파일한 JavaScript를 Node.js에서 실행한다.