Show 만세! 한국어 버전이 드디어 출시되었습니다! 피드백을 공유하거나 오류를 보고하려면 메시지를 보내주세요.
다음 이름으로도 불립니다: 중개인, 컨트롤러, Mediator
중재자는 객체 간의 혼란스러운 의존 관계들을 줄일 수 있는 행동 디자인 패턴입니다. 이 패턴은 객체 간의 직접 통신을 제한하고 중재자 객체를 통해서만 협력하도록 합니다. 문제고객들의 프로필을 만들고 편집하기 위한 대화 상자가 있다고 가정해 봅시다. 이 대화 상자는 텍스트 필드, 체크 상자, 버튼 등과 같은 다양한 양식 컨트롤들로 구성됩니다. 앱이 발전함에 따라 사용자 인터페이스 요소 간의 관계가 혼란스러워질 수 있습니다. 일부 양식 요소들은 다른 요소들과 상호 작용할 수 있습니다. 예를 들어, '저는 개가 있습니다' 확인란을 선택하면 개의 이름을 입력하기 위한 숨겨진 텍스트 필드가 나타날 수 있습니다. 또 다른 예시로 데이터를 저장하기 전에 모든 필드의 값들을 검증해야 하는 제출 버튼이 있습니다. 요소들은 다른 요소들과 많은 관계를 맺을 수 있습니다. 따라서 일부 요소들을 변경하면 다른 요소들에 영향을 줄 수 있습니다. 이 논리를 양식 요소들의 코드 내에서 직접 구현하면 이러한 요소들의 클래스들을 앱의 다른 양식들에서 재사용하기가 훨씬 더 어려워집니다. 예를 들어, 다른 양식 내에서는 위에 언급한 개 관련 확인란 클래스를 사용할 수 없습니다. 왜냐하면 기존 클래스가 개의 이름을 입력하기 위한 텍스트 필드와 결합되어 있기 때문입니다. 이 경우 프로필 양식 렌더링과 관련된 클래스들을 전부 사용하거나 아니면 아예 사용하지 말아야 합니다. 해결책중재자 패턴은 서로 독립적으로 작동해야 하는 컴포넌트 간의 모든 직접 통신을 중단한 후, 대신 이러한 컴포넌트들은 호출들을 적절한 컴포넌트들로 리다이렉션하는 특수 중재자 객체를 호출하여 간접적으로 협력하게 하라고 제안합니다. 그러면 컴포넌트들은 수십 개의 동료 컴포넌트들과 결합되는 대신 단일 중재자 클래스에만 의존합니다. 위 프로필 편집 양식 예시에서는 대화 상자 클래스 자체가 중재자 역할을 할 수 있습니다. 아마도 대화 상자 클래스는 이미 자신의 모든 하위 요소들을 인식하고 있으므로 새로운 의존관계들을 도입할 필요가 없을 것입니다. UI 요소들은 다른 UI 요소들과 중재자 객체를 통해 간접적으로 통신해야 합니다. 가장 중요한 변경들은 실제 양식 요소들에 적용됩니다. 제출 버튼을 살펴보면 이전에는 사용자가 이 버튼을 클릭할 때마다 버튼은 모든 개별 양식 요소들의 값들을 검증해야 했습니다. 이제 제출 버튼이 해야 할 유일한 일은 클릭을 대화 상자에 알리는 것 하나입니다. 이 알림을 받으면 대화 상자는 스스로 검증을 수행하거나 개별 요소들에게 작업을 전달합니다. 따라서 버튼은 여러 개의 양식 요소들에 연결되는 대신 대화 상자 클래스에만 의존하게 됩니다. 여기서 더 나아가 모든 유형의 대화 상자에서 공통 인터페이스를 추출하여 의존성을 더욱 느슨하게 만들 수 있습니다. 이 인터페이스는 모든 양식 요소가 해당 요소들에 발생하는 일(이벤트)들을 대화 상자에 알리는 데 사용할 수 있는 알림 메서드를 선언합니다. 이렇게 하면 제출 버튼은 이제 해당 인터페이스를 구현하는 모든 대화 상자들과 작업할 수 있습니다. 그렇게 하면, 중재자 패턴은 단일 중재자 객체 내부의 다양한 객체 간의 복잡한 관계망을 캡슐화할 수 있도록 합니다. 클래스의 의존관계들이 적을수록 해당 클래스를 수정, 확장 또는 재사용하기가 더 쉬워집니다. 실제상황 적용항공기 조종사들은 다음에 누가 비행기를 착륙시킬지를 결정할 때 서로 직접 대화하지 않습니다. 모든 통신은 비행기 관제탑을 통해 이루어집니다. 공항 관제 구역으로 들어오거나 그곳을 떠나는 항공기의 조종사들은 서로 직접 통신하지 않습니다. 대신, 그들은 높은 타워에 앉아서 일하는 항공 교통 관제사와 통신합니다. 항공 교통 관제사가 없다면 조종사들은 공항 근처의 모든 비행기의 존재 여부를 인식하고 수십 명의 다른 조종사들로 구성된 위원회와 착륙 우선순위를 논의해야 합니다. 그러면 비행기 충돌 횟수는 아마도 하늘로 치솟을 것입니다. 관제탑은 전체 비행을 관할하지 않습니다. 다만 관련되는 비행기의 수가 조종사에게는 너무 많을 수 있기에 공항 터미널 지역에서만 제약들을 강제하기 위해 존재합니다. 구조
의사코드이 예시에서 중재자 패턴은 버튼들, 확인란들 및 텍스트 레이블들과 같은 다양한 UI 클래스 간의 상호 의존성을 제거하는 데 도움이 됩니다. UI 대화 상자 클래스들의 구조. 사용자에 의해 작동된 요소는 다른 요소들과 직접 통신하지 않습니다. 대신 이 요소는 중재자에게 이 이벤트(사건)에 대해 알리고 중재자에게 해당 알림과 함께 콘텍스트 정보를 전달합니다. 이 예시에서는 인증 대화 상자 전체가 중재자의 역할을 합니다. 이것은 구상 요소들이 어떻게 협력해야 하는지 알고 있으며 그들의 간접적인 의사소통을 촉진합니다. 이벤트에 대한 알림을 받으면 대화 상자는 이벤트를 처리해야 하는 요소를 결정하고 그 결정에 따라 호출을 리다이렉션합니다. // 중재자 인터페이스는 컴포넌트들에서 사용하는 메서드를 선언하여 다양한 이벤트를 // 중재자에게 알립니다. 중재자는 이러한 이벤트에 반응해 실행을 다른 컴포넌트들에게 // 전달할 수 있습니다. interface Mediator is method notify(sender: Component, event: string) // 구상 중재자 클래스. 개별 컴포넌트들의 얽히고설킨 연결들이 풀리고 중재자로 // 이동되었습니다. class AuthenticationDialog implements Mediator is private field title: string private field loginOrRegisterChkBx: Checkbox private field loginUsername, loginPassword: Textbox private field registrationUsername, registrationPassword, registrationEmail: Textbox private field okBtn, cancelBtn: Button constructor AuthenticationDialog() is // 연결을 설립하기 위해 현재 중재자를 컴포넌트 객체들의 생성자들에 // 전달하여 모든 컴포넌트 객체들을 생성하세요. // 컴포넌트에 무슨 일어나면, 중재자에게 알립니다. 알림을 받으면 중재자는 // 자체적으로 알림을 처리하거나 요청을 다른 컴포넌트에 전달할 수 있습니다. method notify(sender, event) is if (sender == loginOrRegisterChkBx and event == "check") if (loginOrRegisterChkBx.checked) title = "Log in" // 1. 로그인 양식 컴포넌트들을 표시하세요. // 2. 등록 양식 컴포넌트들을 표시하세요. else title = "Register" // 1. 등록 양식 컴포넌트들을 표시하세요. // 2. 로그인 양식 컴포넌트들을 숨기세요. if (sender == okBtn && event == "click") if (loginOrRegister.checked) // 로그인 자격 증명을 사용하여 사용자를 찾아보세요. if (!found) // 로그인 필드 위에 오류 메시지를 표시하세요. else // 1. 등록 필드의 데이터를 사용하여 사용자 계정을 만드세요. // 2. 해당 사용자를 로그인시키세요. // … // 컴포넌트들은 중재자 인터페이스를 사용하여 중재자와 통신합니다. 덕분에 컴포넌트들을 // 다른 중재자 객체들과 연결하여 다른 콘텍스트에서 같은 컴포넌트들을 사용할 수 // 있습니다. class Component is field dialog: Mediator constructor Component(dialog) is this.dialog = dialog method click() is dialog.notify(this, "click") method keypress() is dialog.notify(this, "keypress") // 구상 컴포넌트들은 서로 통신하지 않습니다. 그들은 하나의 통신 채널만 가지고 // 있으며, 이 채널을 통해 중재자에게 알림들을 보냅니다. class Button extends Component is // … class Textbox extends Component is // … class Checkbox extends Component is method check() is dialog.notify(this, "check") // … 적용중재자 패턴은 일부 클래스들이 다른 클래스들과 단단하게 결합하여 변경하기 어려울 때 사용하세요. 중재자 패턴을 사용하면 특정 컴포넌트에 대한 모든 변경을 나머지 컴포넌트들로부터 고립하며 클래스 간의 모든 관계들을 별도의 클래스로 추출할 수 있습니다. 이 패턴은 타 컴포넌트들에 너무 의존하기 때문에 다른 프로그램에서 컴포넌트를 재사용할 수 없는 경우 사용하세요. 중재자 패턴을 적용하면, 그 후 개별 컴포넌트들은 다른 컴포넌트들을 인식하지 못합니다. 또, 비록 간접적이기는 하지만 컴포넌트들은 중재자 객체를 통해 여전히 서로 통신할 수 있습니다. 다른 앱에서 컴포넌트를 재사용하려면 그 앱에 새 중재자 클래스를 제공해야 합니다. 중재자 패턴은 몇 가지 기본 행동을 다양한 콘텍스트들에서 재사용하기 위해 수많은 컴포넌트 자식 클래스들을 만들고 있는 스스로를 발견했을 때 사용하세요. 컴포넌트들 간의 모든 관계들이 중재자 내에 포함되어 있으므로 컴포넌트들 자체를 변경할 필요 없이 새 중재자 클래스들을 도입하여 이러한 컴포넌트들이 협업할 수 있는 완전히 새로운 방법들을 쉽게 정의할 수 있습니다. 구현방법
장단점
다른 패턴과의 관계
|