# Mediator Pattern 외부 인사가 최근에 코드를 검토한 결과, 현재의 코드에 문제가 많다고 한다. 특히 비어코 위어드(Veerco Wierde)씨는 채팅 애플리케이션에서의 강한 결합(tight coupling)을 지적하고 있다. 이브: 강한 결합이 뭐죠? 페드로: 한 객체가 다른 객체에 대해 너무 많은 것을 알고 있을 때 나타나는 문제예요. 이브: 좀더 구체적으로 설명해 주실 수 있겠어요? 페드로: 현재의 채팅 프로그램 소스를 보시죠. public class User { private String name; List users = new ArrayList(); public User(String name) { this.name = name; } public void addUser(User u) { users.add(u); } void sendMessage(String message) { String text = String.format("%s: %s\n", name, message); for (User u : users) { u.receive(text); } } private void receive(String message) { // process message } } 페드로: 여기서의 문제는 사용자가 모든 다른 사용자들에 관한 정보를 갖고 있다는 것이죠. 이런 코드를 사용하고 유지/보수 하는 것은 대단히 어렵죠. 새로운 사용자가 이 채팅에 들어올 때마다, 모든 사용자가 addUser 메소드를 통해 그 사용자에 대한 레퍼런스를 추가해야만 하거든요. 이브: 그러면 그 일에 해당하는 부분을 다른 클래스로 옮기면 되지 않나요? 페드로: 어느 정도는 맞아요. 모든 사용자들을 관리하는 중개자(mediator)라고 불리는 클래스를 만들면 돼요. 각 사용자는 이 중개자 객체만을 내부에 담게 되죠. public class User { String name; private Mediator m; public User(String name, Mediator m) { this.name = name; this.m = m; } public void sendMessage(String text) { m.sendMessage(this, text); } public void receive(String text) { // process message } } public class Mediator { List users = new ArrayList(); public void addUser(User u) { users.add(u); } public void sendMessage(User u, String text) { for (User user : users) { u.receive(text); } } } 이브: 이것은 단순한 리팩토링 문제같이 보이는 데요. 페드로: 그럴 수도 있지만, 예를 들어, Ui에서 서로 결합된 수백개의 부품들(components)이 있는 경우에는 이 중개자 패턴이 구세주 역할을 할 수 있어요. 이브: 인정합니다. 페드로: 클로저에서는 이런 경우 어떻게 처리하죠? 이브: 음…​ 보아 하니…​ 중개자라는 것이 하는 일이 사용자들을 저장하고 메시지를 보내는 것이네요. (def mediator (atom {:users [] :send (fn [users text] (map #(receive % text) users))})) (defn add-user [u] (swap! mediator (fn [m] (update-in m [:users] conj u)))) (defn send-message [u text] (let [send-fn (:send @mediator) users (:users @mediator)] (send-fn users (format "%s: %s\n" (:name u) text)))) (add-user {:name "Mister White"}) (add-user {:name "Mister Pink"}) (send-message {:name "Joe"} "Toby?") 페드로: 아주 좋네요. 이브: 여기에 특별한 것은 없어요. 단지 결합도를 줄이는 방법 중의 하나일 뿐이니까요.