The Mediator Pattern
Observer 패턴의 섹션에서는 단일 객체를 통해 여러 이벤트 소스를 채널링하는 방법을 소개했습니다. 게시 / 구독 또는 이벤트 집계라고도합니다. 개발자가이 문제에 직면 할 때 중재자를 생각하는 것이 일반적이므로, 어떻게 다른지 살펴 보겠습니다.
사전이란 협상 및 갈등 해소를 지원하는 중립적 인 당으로서 중재자를 지칭합니다. 우리 세계에서 중개자는 시스템의 다른 부분이 통신 할 수있는 통일 된 인터페이스를 노출 할 수있는 행동 설계 패턴입니다.
시스템에 구성 요소 간 직접적인 관계가 너무 많으면 구성 요소가 대신 통신하는 중앙 제어 지점이 필요할 수 있습니다. 중재자는 구성 요소가 명시 적으로 서로를 참조하는 대신 상호 작용이이 중심점을 통해 처리되도록 보장하여 느슨한 결합을 촉진합니다. 이는 시스템을 분리하고 구성 요소 재사용 가능성을 향상시키는 데 도움이 될 수 있습니다.
현실 세계의 비유가 일반적인 공항 교통 통제 시스템이 될 수 있습니다. 탑 (중재자)은 모든 통신 (통보 또는 방송이 청취되는 알림)이 비행기에서 비행기가 아닌 비행기에서 제어 탑으로 이루어지기 때문에 어떤 비행기가 이륙하고 착륙 할 수 있는지 처리합니다. 중앙 집중식 컨트롤러가이 시스템의 성공의 열쇠이며, 이는 중재자가 소프트웨어 설계에서 실제로하는 역할입니다.
또 다른 비유로는 DOM 이벤트 버블 링 및 이벤트 위임이 있습니다. 시스템의 모든 서브 스크립 션이 개별 노드가 아닌 문서와 대조되는 경우 문서는 실제로 중개자의 역할을합니다. 개별 노드의 이벤트에 바인딩하는 대신 상위 수준의 개체는 구독자에게 상호 작용 이벤트를 알리는 역할을합니다.
Mediator 및 Event Aggregator 패턴에 관해서는 구현 유사성으로 인해 패턴이 서로 바뀔 수있는 것처럼 보이는 경우가 있습니다. 그러나 이러한 패턴의 의미와 의도는 매우 다릅니다.
구현이 둘 다 동일한 핵심 구조를 사용하더라도 두 요소간에 뚜렷한 차이가 있다고 생각합니다. 나는 또한 그들이 차이 때문에 의사 소통에있어서 혼동되어서는 안된다고 믿는다.
A Simple Mediator
Mediator는 여러 객체 간의 상호 작용 (논리 및 동작)을 조정하는 객체입니다. 다른 객체 및 입력의 동작 (또는 비 활동)을 기반으로 어떤 객체를 호출 할 것인지 결정합니다.
한 줄의 코드를 사용하여 중개자를 작성할 수 있습니다.
var mediator = {};
네, 물론 이것은 자바 스크립트에서 객체 리터럴 일뿐입니다. 다시 한번, 우리는 여기에서 의미론에 대해 이야기하고 있습니다. 중개자의 목적은 객체 간의 작업 흐름을 제어하는 것이며,이를 수행하기 위해 객체 리터럴 이상을 필요로하지 않습니다.
var orgChart = {
addNewEmployee: function(){
// getEmployeeDetail provides a view that users interact with
var employeeDetail = this.getEmployeeDetail();
// when the employee detail is complete, the mediator (the 'orgchart' object)
// decides what should happen next
employeeDetail.on("complete", function(employee){
// set up additional objects that have additional events, which are used
// by the mediator to do additional things
var managerSelector = this.selectManager(employee);
managerSelector.on("save", function(employee){
employee.save();
});
});
},
// ...
}
이 예제는 이벤트를 트리거하고 구독 할 수있는 몇 가지 유틸리티 메소드가있는 중재자 객체의 매우 기본적인 구현을 보여줍니다.
저는 종종이 유형의 객체를 과거에 "워크 플로"객체라고 부르지 만 사실은 그것이 중재자라는 것입니다. 그것은 많은 다른 객체들 사이의 워크 플로우를 처리하고, 그 워크 플로우 지식의 책임을 하나의 객체로 모으는 객체입니다. 그 결과 워크 플로우를 이해하고 유지하기가 더 쉽습니다.
유사점과 차이점
의심의 여지없이 이벤트 수집 자와 여기에 표시된 중재자 예제간에 유사점이 있습니다. 유사점은 두 가지 기본 항목 인 이벤트 및 타사 개체로 요약됩니다. 이러한 차이점은 기껏해야 표면적입니다. 우리가 패턴의 의도를 파고 들고 구현이 크게 다를 수 있다는 것을 알게되면, 패턴의 본질이 더욱 분명해진다.
이벤트
위의 예에서 이벤트 수집기와 조정자 모두 이벤트를 사용합니다. 이벤트 수집기는 분명히 이벤트를 처리합니다. 중재자는 최신 JavaScript 웹 응용 프로그램 프레임 워크를 처리 할 때 일상적인 작업을하기 때문에 이벤트 만 사용합니다. 중재자가 사건으로 건설되어야한다고 말하는 것은 없습니다. 중재자 참조를 자식 객체에 넘겨 주거나 다른 여러 가지 방법으로 콜백 메소드로 중재자를 만들 수 있습니다.
차이점은이 두 패턴이 둘 다 이벤트를 사용하는 이유입니다. 이벤트 수집자는 패턴으로 이벤트를 처리하도록 설계되었습니다. 중재자는 편리하기 때문에 단지 그것을 사용합니다.
Third-Party Objects
이벤트 집계 자 및 조정자는 의도적으로 일을 용이하게하기 위해 제 3 자 개체를 사용합니다. 이벤트 수집기 자체는 이벤트 게시자 및 이벤트 구독자의 제 3 자입니다. 이벤트가 전달되는 중앙 허브 역할을합니다. 하지만 중재자는 다른 사물의 제 3 자이기도합니다. 차이점은 무엇입니까? 이벤트 애그리 게이터를 중재자 (mediator)라고 부르는 이유는 무엇입니까? 대답은 주로 응용 프로그램 논리와 워크 플로가 코딩되는 곳으로옵니다.
이벤트 애그리 게이터의 경우, 제 3 자 객체는 알 수없는 소스의 이벤트를 알려지지 않은 수의 핸들러로 전달하는 것을 용이하게합니다. 시작되어야하는 모든 워크 플로와 비즈니스 논리는 이벤트를 처리하는 개체와 이벤트를 처리하는 개체에 직접 배치됩니다.
하지만 중재자의 경우 비즈니스 로직과 워크 플로가 중재자 자체로 통합됩니다. 중재자는 객체가 호출되어야하는 메소드를 결정해야하며 중재자가 알고있는 요소를 기반으로 속성을 업데이트합니다. 워크 플로와 프로세스를 캡슐화하여 여러 개체를 조정하여 원하는 시스템 동작을 생성합니다. 이 워크 플로와 관련된 개별 개체는 각각 자신의 작업을 수행하는 방법을 알고 있습니다. 그러나 개체를 개별 개체보다 높은 수준에서 결정함으로써 작업을 수행 할시기를 알려주는 것이 중재자입니다.
이벤트 수집기는 통신의 "화재 및 잊어 버리기"모델을 용이하게합니다. 이벤트를 트리거하는 객체는 구독자가 있는지 상관하지 않습니다. 이벤트를 시작하고 계속 진행합니다. 중재자는 사건을 사용하여 결정을 내릴 수도 있지만, 분명히 "불이나 잊지"는 아닙니다. 조정자 (mediator)는 알려진 일련의 입력 또는 활동에주의를 기울여 알려진 액터 (객체) 세트를 사용하여 추가 동작을 용이하게하고 조정할 수 있습니다.
관계 : 언제 사용 하는가
의미 수집을 위해서는 이벤트 수집 자와 중재자 간의 유사점과 차이점을 이해하는 것이 중요합니다. 어떤 패턴을 사용해야 하는지를 이해하는 것이 중요합니다. 패턴의 기본 의미와 의도는 언제의 문제인지를 알려주지 만 패턴을 실제로 사용한 경험을 통해 미묘한 점과 미묘한 차이를 이해하는 데 도움이됩니다.
이벤트 수집기 사용
일반적으로 이벤트 수집기는 너무 많은 객체를 사용하여 직접 듣거나 객체와 완전히 관련이없는 경우에 사용됩니다.
두 객체가 이미 부모 뷰와 하위 뷰와 같은 직접적인 관계가있는 경우 이벤트 수집기 사용시 이점이있을 수 있습니다. 하위보기에서 이벤트를 트리거하고 상위보기에서 이벤트를 처리하도록하십시오. JavaScript 프레임 워크 측면에서 보았을 때 이것은 Backbone의 Collection 및 Model에서 가장 일반적으로 볼 수 있습니다. 여기에서 모든 Model 이벤트는 상위 Collection까지 이어집니다. 컬렉션은 종종 모델 이벤트를 사용하여 자체 또는 다른 모델의 상태를 수정합니다. 컬렉션에서 "선택된"항목을 처리하는 것이 좋은 예입니다.
이벤트 애그리 게이터 (event aggregator) 인 jQuery의 메소드는 너무 많은 객체를 듣기 좋은 예제이다. "클릭"이벤트를 유발할 수있는 DOM 요소가 10 개, 20 개 또는 200 개일 경우 모든 요소에 대해 개별적으로 수신기를 설정하는 것은 좋지 않을 수 있습니다. 이로 인해 응용 프로그램 및 사용자 환경의 성능이 빠르게 저하 될 수 있습니다. 대신 jQuery의 on 메서드를 사용하면 모든 이벤트를 집계하고 10, 20 또는 200 이벤트 핸들러의 오버 헤드를 1까지 줄일 수 있습니다.
간접적 인 관계는 이벤트 수집기를 사용하기에도 좋습니다. 현대 응용 프로그램에서는 의사 소통이 필요하지만 직접적인 관계가없는 여러보기 개체를 갖는 것이 일반적입니다. 예를 들어, 메뉴 시스템에는 메뉴 항목 클릭을 처리하는보기가있을 수 있습니다. 그러나 메뉴 항목을 클릭 할 때 모든 세부 정보와 정보를 보여주는 컨텐트보기에 메뉴가 직접 연결되는 것을 원하지는 않습니다. 컨텐츠와 메뉴가 결합되면 장기적으로 코드를 유지 관리하기가 매우 어려워집니다. 대신 이벤트 수집기를 사용하여 "menu : click : foo"이벤트를 트리거하고 "foo"객체가 click 이벤트를 처리하여 해당 내용을 화면에 표시하도록 할 수 있습니다.
Mediator 사용
중재자는 두 개 이상의 객체가 간접적 인 작업 관계를 가지고 비즈니스 로직이나 워크 플로우가 이러한 객체의 상호 작용과 조정을 지시해야 할 때 가장 잘 적용됩니다.
위의 "orgChart"예제와 같이 마법사 인터페이스가 좋은 예입니다. 마법사의 전체 워크 플로를 지원하는보기가 여러 개 있습니다. 서로를 직접 참조하게하여 뷰를 단단히 연결하는 대신, 중재자를 도입하여 뷰를 분리하고 명시 적으로 워크 플로를 모델링 할 수 있습니다.
중재자는 구현 세부 사항에서 워크 플로를 추출하고 더 높은 수준에서보다 자연스러운 추상화를 생성하여 워크 플로우가 훨씬 더 빠르게 파악되도록합니다. 우리는 더 이상 워크 플로우의 각 뷰에 대한 세부 사항을 파헤쳐 실제로 워크 플로우가 무엇인지 확인할 필요가 없습니다.
이벤트 수집기 (Pub / Sub) 및 중재자 함께 사용
이벤트 애그리 게이터와 중재자의 차이점과 이러한 패턴 이름을 서로 교환해서는 안되는 이유는이 패턴 이름을 함께 사용하는 방법을 보여줌으로써 가장 잘 보여줍니다. 이벤트 수집기의 메뉴 예제는 중재자를 소개하기에 완벽한 장소입니다.
메뉴 항목을 클릭하면 응용 프로그램 전체에서 일련의 변경 사항이 트리거 될 수 있습니다. 이러한 변경 사항 중 일부는 다른 이벤트와 독립적이며, 이벤트 수집기를 사용하는 것이 좋습니다. 이러한 변경 사항 중 일부는 내부적으로 서로 관련되어있을 수 있으며 이러한 변경 사항을 적용하기 위해 중재자를 사용할 수 있습니다.
조정자는 이벤트 수집기를 청취하도록 설정할 수 있습니다. 서로 관련이 있지만 원래 이벤트 소스와 관련이없는 많은 오브젝트를 손쉽게 조정하고 조정할 수있는 논리와 프로세스를 실행할 수 있습니다.
var MenuItem = MyFrameworkView.extend({
events: {
"click .thatThing": "clickedIt"
},
clickedIt: function(e){
e.preventDefault();
// assume this triggers "menu:click:foo"
MyFramework.trigger("menu:click:" + this.model.get("name"));
}
});
// ... somewhere else in the app
var MyWorkflow = function(){
MyFramework.on("menu:click:foo", this.doStuff, this);
};
MyWorkflow.prototype.doStuff = function(){
// instantiate multiple objects here.
// set up event handlers for those objects.
// coordinate all of the objects into a meaningful workflow.
};
이 예제에서 올바른 모델이있는 MenuItem을 클릭하면 "menu : click : foo"
이벤트가 트리거됩니다. "MyWorkflow"객체의 인스턴스가 이미 인스턴스화되었다고 가정하면이 특정 이벤트를 처리하고 알고있는 모든 객체를 조정하여 원하는 사용자 경험과 워크 플로우를 만듭니다.
이벤트 애그리 게이터와 중재자가 결합되어 코드와 애플리케이션 자체에서 훨씬 의미있는 경험을 제공합니다. 이제는 이벤트 수집기를 통해 메뉴와 워크 플로간에 명확한 구분이 이루어졌으며 중재자를 사용하여 워크 플로 자체를 깨끗하고 유지 관리 할 수 있습니다.
장점 & 단점
Mediator 패턴의 가장 큰 이점은 시스템의 객체 또는 구성 요소간에 필요한 통신 채널을 여러에서 많은 것에서 많은 것부터 하나의 것까지 줄이는 것입니다. 새로운 게시자와 구독자를 추가하는 것은 현재 디커플링 수준으로 인해 상대적으로 쉽습니다.
아마도이 패턴을 사용하는 가장 큰 단점은 단일 실패 지점을 도입 할 수 있다는 것입니다. 모듈간에 중개자를 배치하면 간접적으로 통신하기 때문에 성능에 영향을 줄 수 있습니다. 느슨한 커플 링의 특성 때문에 방송을 보는 것만으로 시스템이 어떻게 반응 할지를 결정하기가 어렵습니다.
즉, 분리 된 시스템은 여러 가지 다른 이점을 가지고 있음을 상기시키는 것이 유용합니다. 모듈이 서로 직접 통신하는 경우 모듈 변경 (예 : 예외 발생의 다른 모듈)이 나머지 응용 프로그램에 쉽게 영향을 미칠 수 있습니다 . 이 문제는 분리 된 시스템에 대한 우려가 적습니다.
결국, 단단한 커플 링은 모든 종류의 두통을 야기하며 이것은 또 다른 대안의 해결책 일 뿐이지 만 올바르게 구현되면 매우 잘 작동 할 수 있습니다.
Mediator Vs. Facade
우리는 곧 Facade 패턴을 다루 겠지만, 참고 용으로 일부 개발자는 중재자와 Facade 패턴간에 유사점이 있는지 궁금해 할 수도 있습니다. 둘 다 기존 모듈의 기능을 추상화하지만 약간의 차이점이 있습니다.
Mediator는 모듈간에 명시 적으로 참조되는 모듈 간의 통신을 중앙 집중식으로 처리합니다. 어떤 의미에서 이것은 다방면입니다. Facade는 모듈 또는 시스템에 대한 간단한 인터페이스를 정의하지만 추가 기능은 추가하지 않습니다. 시스템의 다른 모듈은 정면의 개념을 직접 인식하지 못하고 단방향으로 간주 될 수 있습니다.