당신은 주제를 찾고 있습니까 “중재자 패턴 – GoF의 Design Pattern – 12. Mediator“? 다음 카테고리의 웹사이트 you.maxfit.vn 에서 귀하의 모든 질문에 답변해 드립니다: you.maxfit.vn/blog. 바로 아래에서 답을 찾을 수 있습니다. 작성자 GIS DEVELOPER 이(가) 작성한 기사에는 조회수 214회 및 좋아요 8개 개의 좋아요가 있습니다.
중재자 패턴 주제에 대한 동영상 보기
여기에서 이 주제에 대한 비디오를 시청하십시오. 주의 깊게 살펴보고 읽고 있는 내용에 대한 피드백을 제공하세요!
d여기에서 GoF의 Design Pattern – 12. Mediator – 중재자 패턴 주제에 대한 세부정보를 참조하세요
안녕하세요, GIS Developer 김형준입니다.
GoF의 디자인패턴 중 Mediator 패턴에 대한 내용입니다.
Mediator 패턴은 객체들 간의 복잡한 관계를 중재자라는 것을 두어 매우 효과적으로 단순화 시킵니다.
영상을 보시고 문의 사항이 있으시면 댓글을 통해 남겨주세요~
중재자 패턴 주제에 대한 자세한 내용은 여기를 참조하세요.
[Design Pattern] 중재자 패턴 (Mediator Pattern) – 불곰 :: 불곰
중재자 패턴은 클래스 간의 복잡한 관계들을 캡슐화하여 하나의 클래스에서 관리하도록 처리하는 패턴입니다. M:N 관계를 해당 패턴을 사용하면 M:1 …
Source: brownbears.tistory.com
Date Published: 2/14/2022
View: 8077
중재자 패턴 – 위키백과, 우리 모두의 백과사전
중재자 패턴(mediator pattern), 조정자 패턴은 소프트웨어 공학에서 어떻게 객체들의 집합이 상호작용하는지를 함축해놓은 객체를 정의한다. 이 패턴은 프로그램의 …
Source: ko.wikipedia.org
Date Published: 6/15/2022
View: 663
[Java][디자인 패턴] 19. 중재자 패턴 (Mediator Pattern)
중재자 패턴은 객체의 관계를 하나의 객체로 정리하는 패턴이다. · 중자재 패턴은 서로 의존적인 M:N 관계를 가진 객체를 느슨한 1:1 관계로 변경한다 …
Source: hirlawldo.tistory.com
Date Published: 1/6/2021
View: 6309
[디자인패턴][Mediator] 중재자 패턴 – 소프트웨어에 대한 모든 것
중재자 패턴 정의. 클래스 간의 복잡한 관계들을 캡슐화하여 하나의 클래스에서 관리하도록 처리하는 패턴; M개의 객체들 사이에 중재자를 추가하여 …
Source: wellsw.tistory.com
Date Published: 4/22/2022
View: 2617
주제와 관련된 이미지 중재자 패턴
주제와 관련된 더 많은 사진을 참조하십시오 GoF의 Design Pattern – 12. Mediator. 댓글에서 더 많은 관련 이미지를 보거나 필요한 경우 더 많은 관련 기사를 볼 수 있습니다.
주제에 대한 기사 평가 중재자 패턴
- Author: GIS DEVELOPER
- Views: 조회수 214회
- Likes: 좋아요 8개
- Date Published: 2022. 1. 18.
- Video Url link: https://www.youtube.com/watch?v=ZvyxRzma1UY
Crocus
반응형
중재자 패턴(Mediator Pattern)
모든 클래스간의 복잡한 로직(상호작용)을 캡슐화하여 하나의 클래스에 위임하여 처리하는 패턴이다.
즉, M:N의 관계에서 M:1의 관계로 복잡도를 떨어뜨려 유지 보수 및 재사용의 확장성에 유리한 패턴이다.
커뮤니케이션을 하고자 하는 객체가 있을 때 서로가 커뮤니케이션 하기 복잡한 경우 이를 해결해주고 서로 간 쉽게 해주며 커플링을 약화시켜주는 패턴이다.
객체들간 커뮤니케이션 정의가 잘 돼있으나 복잡할 때(종합이 필요할 때) 사용한다.
이와 비슷한 패턴은 파사드 패턴(Facade Pattern)과 옵저버 패턴(Observer Pattern)이 있다.
위의 그림에서 관제탑이 중재자가 되고 각 비행기가 서로 커뮤니케이션을 하기 위해서는
관제탑을 거쳐 M:N이 아닌 M:1의 관계로 커뮤니케이션을 진행하게 된다.
프로그램을 작성하다 보면 상호작용을 해야하는 경우 객체들 간의 결합도가 증가하고 유연성이 떨어지는 경우가 발생하게 된다.
이때 중재자 패턴에서는 서로 명령을 주고 받을 수 있는 형식이 있다고 했을 때 서로 명령을 주고 받는 부분을 중재하는 형식을 정의를 한다.
그리고, 원래 서로 명령을 주고 받았던 개체들은 중재자 개체를 알게 하고 중재자 개체는 이들 개체를 알게 한다.
이제 특정 개체가 명령을 내릴 필요가 있으면 중재자 개체에게 전달하기만 하면 되고,
중재자는 해당 명령을 자신이 알고 있는 개체들 중에 적절한 개체에게 전달만 하면 된다.
이처럼 중재자 패턴을 사용하면 복잡한 상호작용을 하기 위한 복잡한 관계를 단순화시킬 수 있게 된다.
그리고 중재자가 notify한다는 의미로 옵저버 패턴과 매우 유사한데,
옵저버는 Subscriber이 받기만 하는데 Mediator은 서로 통신한다는 것에서 차이가 있다.
중재자 패턴 클래스 다이어그램
+Mediator은 Colleague가 Mediator에서 알려주는 것을 의미하고
ColleagueA도 마찬가지로 Mediator가 ColleagueA,B에게 알리는 것을 의미한다.
중재자 패턴 예제
Isource 인터페이스
package MediatorPattern; interface ISource{ public void setMediator(Mediator mediator); public void eventOccured(String event); }
TcpComm 클래스
ISource를 구현하는 Concrete 부분.
mediator을 설정하고 mediator에게 onEvent로 메시지를 전달한다.
package MediatorPattern; public class TcpComm implements ISource { Mediator mediator; @Override public void setMediator(Mediator mediator){ // 중재자 설정 this.mediator = mediator; } @Override public void eventOccured(String event){ // 이벤트의 전달 mediator.onEvent(“TCP comm”, event); } }
SystemSignal 클래스
TcpComm 클래스와 같다.
package MediatorPattern; class SystemSignal implements ISource{ Mediator mediator; @Override public void setMediator(Mediator mediator){ // 중재자 설정 this.mediator = mediator; } @Override public void eventOccured(String event){ // 이벤트의 전달 mediator.onEvent(“System”, event); } }
Mediator 클래스
onEvent를 받으면 해당하는 메시지를 receiveEvent를 통해 보낸다.
package MediatorPattern; import java.util.ArrayList; import java.util.List; class Mediator{ List
list = new ArrayList (); public void addDestination(IDestination destination){ list.add(destination); } public void onEvent(String from, String event){ for(IDestination each : list){ // 이벤트의 전송 each.receiveEvent(from, event); } } } IDestionation 인터페이스
package MediatorPattern; interface IDestination{ public void receiveEvent(String from, String event); }
Display 클래스
Idestianation 인터페이스를 구현하고 있다.
package MediatorPattern; class Display implements IDestination{ @Override public void receiveEvent(String from, String event){ System.out.println(“Display : from ” + from + ” event : ” + event); } }
Log 클래스
Display 클래스와 같다.
package MediatorPattern; class Log implements IDestination{ @Override public void receiveEvent(String from, String event){ System.out.println(“Log : from ” + from + ” event : ” + event); } }
MediatorMain 클래스
각 생성자를 만들고 destination은 Display, Log로 해준후 이벤트를 전달하여 아래와 같은 결과값을 얻을 수 있다.
package MediatorPattern; public class MediatorMain { public static void main(String[] args) { Mediator mediator = new Mediator(); ISource tcp = new TcpComm(); tcp.setMediator(mediator); ISource system = new SystemSignal(); system.setMediator(mediator); mediator.addDestination(new Display()); mediator.addDestination(new Log()); tcp.eventOccured(“connected”); tcp.eventOccured(“disconnected”); system.eventOccured(“key input”); system.eventOccured(“mouse input”); } }
Display : from TCP comm event : connected
Log : from TCP comm event : connected
Display : from TCP comm event : disconnected
Log : from TCP comm event : disconnected
Display : from System event : key input
Log : from System event : key input
Display : from System event : mouse input
Log : from System event : mouse input
중재자 패턴 예제 출처
https://effectiveprogramming.tistory.com/entry/Mediator-%ED%8C%A8%ED%84%B4
반응형
[Design Pattern] 중재자 패턴 (Mediator Pattern)
중재자 패턴은 클래스 간의 복잡한 관계들을 캡슐화하여 하나의 클래스에서 관리하도록 처리하는 패턴입니다. M:N 관계를 해당 패턴을 사용하면 M:1 관계로 만들어 복잡도를 내리므로 유지 보수 및 확장성에 유리합니다.
M개의 객체들 사이에 중재자를 추가하여 중재자가 모든 객체들의 통신을 담당하도록 변경하면 중재자 패턴이라 볼 수 있습니다. 이와 같이 진행하면 각 객체들은 서로 알 필요가 없고 중재자 클래스가 관리하므로 느슨한 결합(loose coupling)을 유지할 수 있고 전체적인 흐름을 읽기 편해집니다.
단점으로는 특정 application에 맞춰져서 개발이 되기 때문에 재사용이 어렵습니다.
이와 유사한 패턴으로는 퍼사드 패턴(https://brownbears.tistory.com/507)과 옵저버 패턴(https://brownbears.tistory.com/555)이 있습니다.
클래스 다이어그램
Mediator: Colleague 객체 간의 상호참조를 위한 인터페이스. 클라이언트 등록, 실행 등의 메소드 정의
Colleague: 다른 Colleague와의 상호참조를 위한 인터페이스.
ConcreteMediator: Mediator 구현 클래스. Colleague 간의 상호참조를 조정
ConcreteColleage: Colleague 구현 클래스. Mediator를 통해 다른 Colleague와의 상호참조
옵저버 패턴, 퍼사드 패턴과의 차이점
퍼사드 패턴
1통신을 위해 인터페이스를 설계하고 제공한다는 점에서 두 패턴은 동일하지만 퍼사드 패턴은 단방향 통신만 가능하지만 중재자 패턴은 양방향 통신을 지원합니다.
옵저버 패턴
옵저버 패턴은 1개의 publisher에 대해 N개의 subscriber가 존재하고 observer가 pulling이나 push 방식을 통해 관리하지만 중재자 패턴은 M개의 publisher와 N개의 subscriber 사이에서 1개의 mediator를 통해 통신을 하는 방식입니다.
예시
아래는 채팅을 구현한 예시입니다.
public interface Mediator { void addUser(Colleague user); void deleteUser(Colleague user); void sendMessage(String message, Colleague user); } public abstract class Colleague { protected Mediator mediator; protected String name; public Colleague(Mediator mediator, String name) { this.mediator = mediator; this.name = name; } public abstract void send(String msg); public abstract void receive(String msg); } public class ConcreteMediator implements Mediator { private final List
users; public ConcreteMediator() { this.users=new ArrayList<>(); } @Override public void addUser(Colleague user) { this.users.add(user); } @Override public void deleteUser(Colleague user) { this.users.remove(user); } @Override public void sendMessage(String message, Colleague user) { for(Colleague u : this.users){ if(u != user){ u.receive(message); } } } } public class ConcreteColleague extends Colleague { public ConcreteColleague(Mediator mediator, String name) { super(mediator, name); } @Override public void send(String msg) { System.out.println(this.name+”: Sending Message=”+msg); mediator.sendMessage(msg, this); } @Override public void receive(String msg) { System.out.println(this.name+”: Received Message:”+msg); } } Mediator mediator = new ConcreteMediator(); Colleague user1 = new ConcreteColleague(mediator, “lee”); Colleague user2 = new ConcreteColleague(mediator, “kim”); Colleague user3 = new ConcreteColleague(mediator, “park”); Colleague user4 = new ConcreteColleague(mediator, “yon”); mediator.addUser(user1); mediator.addUser(user2); mediator.addUser(user3); mediator.addUser(user4); user1.send(“안녕하세요”); // lee: Sending Message=안녕하세요 // kim: Received Message:안녕하세요 // park: Received Message:안녕하세요 // yon: Received Message:안녕하세요 mediator.deleteUser(user4); user2.send(“yon없지?”); // kim: Sending Message=yon없지? // lee: Received Message:yon없지? // park: Received Message:yon없지? 파이썬
ABCMeta를 사용해 자바와 동일하게 구현할 수 있습니다.
from abc import ABCMeta, abstractmethod class Colleague(metaclass=ABCMeta): def __init__(self, _mediator, name): self.mediator = _mediator self.name = name @abstractmethod def send(self, msg:str): pass @abstractmethod def receive(self, msg:str): pass class Mediator(metaclass=ABCMeta): @abstractmethod def add_users(self, user): pass @abstractmethod def delete_user(self, user): pass @abstractmethod def send_message(self, msg:str, user): pass class ConcreteMediator(Mediator): def __init__(self): self.users = [] def add_users(self, *users): self.users.extend(users) def delete_user(self, user): self.users.remove(user) def send_message(self, msg: str, user): for _user in self.users: if _user == user: continue _user.receive(msg) class ConcreteColleague(Colleague): def __init__(self, mediator, name): super().__init__(mediator, name) def send(self, msg: str): print(f'{self.name} sending message={msg}’) self.mediator.send_message(msg, self) def receive(self, msg: str): print(f'{self.name} receiving message={msg}’) mediator = ConcreteMediator() user1 = ConcreteColleague(mediator, ‘lee’) user2 = ConcreteColleague(mediator, ‘kim’) user3 = ConcreteColleague(mediator, ‘park’) user4 = ConcreteColleague(mediator, ‘yon’) mediator.add_users(user1, user2, user3, user4) user1.send(“안녕하세요”) mediator.delete_user(user4) user2.send(“yon없지?”)
위키백과, 우리 모두의 백과사전
중재자 패턴(mediator pattern), 조정자 패턴은 소프트웨어 공학에서 어떻게 객체들의 집합이 상호작용하는지를 함축해놓은 객체를 정의한다. 이 패턴은 프로그램의 실행 행위를 변경할 수 있기 때문에 행위 패턴으로 간주된다.
중재자 패턴을 사용하면 객체 간 통신은 중재자 객체 안에 함축된다. 객체들은 더 이상 다른 객체와 서로 직접 통신하지 않으며 대신 중재자를 통해 통신한다. 이를 통해 통신 객체 간 의존성을 줄일 수 있으므로 결합도를 감소시킨다.
개요 [ 편집 ]
중재자[1] 디자인 패턴은 유연하고 재사용 가능한 객체 지향 소프트웨어를 설계하기 위해 반복되는 디자인 문제를 해결하는 방법, 즉 객체는 구현, 변경, 테스트, 재사용이 쉬워야 한다는 것을 기술하는, 잘 알려진 23가지 GoF 디자인 패턴들 중 하나이다.
구조 [ 편집 ]
UML 클래스 및 시퀀스 다이어그램 [ 편집 ] [2] 중재자 디자인 패턴을 위한 샘플 UML 클래스와 시퀀스 다이어그램.
클래스 다이어그램 [ 편집 ]
중재자 행위 디자인 패턴
예시 [ 편집 ]
자바 [ 편집 ]
import java.awt.Font ; import java.awt.event.ActionEvent ; import java.awt.event.ActionListener ; import javax.swing.JButton ; import javax.swing.JFrame ; import javax.swing.JLabel ; import javax.swing.JPanel ; //Colleague interface interface Command { void execute (); } //Abstract Mediator interface Mediator { void book (); void view (); void search (); void registerView ( BtnView v ); void registerSearch ( BtnSearch s ); void registerBook ( BtnBook b ); void registerDisplay ( LblDisplay d ); } //Concrete mediator class ParticipantMediator implements Mediator { BtnView btnView ; BtnSearch btnSearch ; BtnBook btnBook ; LblDisplay show ; //…. public void registerView ( BtnView v ) { btnView = v ; } public void registerSearch ( BtnSearch s ) { btnSearch = s ; } public void registerBook ( BtnBook b ) { btnBook = b ; } public void registerDisplay ( LblDisplay d ) { show = d ; } public void book () { btnBook . setEnabled ( false ); btnView . setEnabled ( true ); btnSearch . setEnabled ( true ); show . setText ( “booking…” ); } public void view () { btnView . setEnabled ( false ); btnSearch . setEnabled ( true ); btnBook . setEnabled ( true ); show . setText ( “viewing…” ); } public void search () { btnSearch . setEnabled ( false ); btnView . setEnabled ( true ); btnBook . setEnabled ( true ); show . setText ( “searching…” ); } } //A concrete colleague class BtnView extends JButton implements Command { Mediator med ; BtnView ( ActionListener al , Mediator m ) { super ( “View” ); addActionListener ( al ); med = m ; med . registerView ( this ); } public void execute () { med . view (); } } //A concrete colleague class BtnSearch extends JButton implements Command { Mediator med ; BtnSearch ( ActionListener al , Mediator m ) { super ( “Search” ); addActionListener ( al ); med = m ; med . registerSearch ( this ); } public void execute () { med . search (); } } //A concrete colleague class BtnBook extends JButton implements Command { Mediator med ; BtnBook ( ActionListener al , Mediator m ) { super ( “Book” ); addActionListener ( al ); med = m ; med . registerBook ( this ); } public void execute () { med . book (); } } class LblDisplay extends JLabel { Mediator med ; LblDisplay ( Mediator m ) { super ( “Just start…” ); med = m ; med . registerDisplay ( this ); setFont ( new Font ( “Arial” , Font . BOLD , 24 )); } } class MediatorDemo extends JFrame implements ActionListener { Mediator med = new ParticipantMediator (); MediatorDemo () { JPanel p = new JPanel (); p . add ( new BtnView ( this , med )); p . add ( new BtnBook ( this , med )); p . add ( new BtnSearch ( this , med )); getContentPane (). add ( new LblDisplay ( med ), “North” ); getContentPane (). add ( p , “South” ); setSize ( 400 , 200 ); setVisible ( true ); } public void actionPerformed ( ActionEvent ae ) { Command comd = ( Command ) ae . getSource (); comd . execute (); } public static void main ( String [] args ) { new MediatorDemo (); } }
같이 보기 [ 편집 ]
[Design Pattern] 중재자 패턴(Mediator Pattern)
중재자 패턴(Mediator Pattern)
행위(Behavioral) 패턴
모든 클래스간의 복잡한 로직(상호작용)을 캡슐화하여 하나의 클래스에 위임하여 처리하는 패턴
M:N의 관계에서 M:1의 관계로 복잡도를 떨어뜨려 유지 보수 및 재사용의 확장성에 유리한 패턴
구조
Mediator 여러 Component 중재해주는 인터페이스를 가지고 있는 추상 클래스 객체
ConcreteMediator Component 객체들을 가지고 있으면서 중재해주는 역할을 하는 객체
Component Mediator 객체에 의해서 관리 및 중재를 받을 기본 클래스 객체들
구현
채팅 구현하기
Colleague.class
public abstract class Colleague { private Mediator mediator ; protected String name ; private String message ; public Colleague ( String name ) { this . name = name ; } public void setMediator ( Mediator mediator ) { this . mediator = mediator ; } public String getName ( ) { return this . name ; } public void setMessage ( String message ) { this . message = message ; } public String getMessage ( ) { return this . message ; } public void send ( ) { System . out . println ( this . name + ” send()” ) ; System . out . println ( ) ; mediator . mediate ( this ) ; } public abstract void receive ( Colleague colleague ) ; }
다른 객체와 통신을 하는 요소다
예제의 User, Admin, System의 추상적인 요소에 해당한다. 통신에 필요한 메서드를 가지고 있다
다른 객체와의 통신은 직접하지 않으며, Mediator 객체를 통해 요청을 하는 방식으로 통신한다
ConcreteColleague1.class
public class ConcreteColleague1 extends Colleague { public ConcreteColleague1 ( String name ) { super ( name ) ; } @Override public void receive ( Colleague colleague ) { System . out . println ( this . name + ” recevied ” + colleague . getName ( ) + “‘s Message : ” + colleague . getMessage ( ) ) ; } }
ConcreteColleague2.class
public class ConcreteColleague2 extends Colleague { public ConcreteColleague2 ( String name ) { super ( name ) ; } @Override public void receive ( Colleague colleague ) { System . out . println ( “System can’t receive messages” ) ; } }
ConcreteColleague3.class
public class ConcreteColleague3 extends Colleague { public ConcreteColleague3 ( String name ) { super ( name ) ; } @Override public void receive ( Colleague colleague ) { System . out . println ( “Admin can’t receive messages” ) ; } }
예제의 User, Admin, System에 해당하는 클래스다
Colleague클래스를 상속받아 통신에 필요한 메서드를 구현해야 한다
User는 메시지를 받을 수 있으나, Admin/System은 보내는 것만 가능하다
Mediator.class
public interface Mediator { void addColleague ( Colleague colleague ) ; void mediate ( Colleague colleague ) ; }
객체간의 통신을 중재하는 클래스다
통신의 대상이 되는 Colleague를 추가하는 메서드가 존재해야 한다
ConcreteMediator.class
public class ConcreteMediator implements Mediator { private List < Colleague > colleagueList ; public ConcreteMediator ( ) { this . colleagueList = new ArrayList < Colleague > ( ) ; } @Override public void addColleague ( Colleague colleague ) { this . colleagueList . add ( colleague ) ; } @Override public void mediate ( Colleague colleague ) { for ( Colleague receiverColleague : colleagueList ) { System . out . println ( “\tMediating ” + colleague . getName ( ) + ” to ” + receiverColleague . getName ( ) ) ; receiverColleague . receive ( colleague ) ; } } }
Mediator를 구현하는, 실질적으로 중재하는 로직을 가지는 클래스다
서로 통신하는 객체들을 가지고있어야 하며, 특정 Colleague로부터 요청이 들어오면, 상대 Colleague를 찾아서 해당 메시지를 전달한다
Mediator는 Colleague에 대한 레퍼런스를 가지고 있고 Colleague는 Mediator에 대한 레퍼런스를 가지고 있다.
즉, 양방향 연관관계(Bi-Directional Associations)를 가진다.
Main.class
public static void main ( String args [ ] ) { Mediator mediator1 = new ConcreteMediator ( ) ; Colleague colleague1 = new ConcreteColleague1 ( “User1” ) ; Colleague colleague2 = new ConcreteColleague1 ( “User2” ) ; Colleague colleague3 = new ConcreteColleague2 ( “System” ) ; Colleague colleague4 = new ConcreteColleague3 ( “Admin” ) ; colleague1 . setMediator ( mediator1 ) ; colleague2 . setMediator ( mediator1 ) ; colleague3 . setMediator ( mediator1 ) ; colleague4 . setMediator ( mediator1 ) ; mediator1 . addColleague ( colleague1 ) ; mediator1 . addColleague ( colleague2 ) ; mediator1 . addColleague ( colleague3 ) ; mediator1 . addColleague ( colleague4 ) ; colleague1 . setMessage ( “I’m User1” ) ; colleague1 . send ( ) ; }
실행결과
>>> User1 send ( ) >>> Mediating User1 to User1 >>> User1 recevied User1 ‘s Message : I’ m User1 >>> Mediating User1 to User2 >>> User2 recevied User1 ‘s Message : I’ m User1 >>> Mediating User1 to System >>> System can’t receive messages >>> Mediating User1 to Admin >>> Admin can’t receive messages
장단점
장점 효율적인 자원 관리(리소스 풀등)를 가능하게 한다 객체간의 통신을 위해 서로간에 직접 참조할 필요가 없게 한다 객체들 간 수정을 하지않고 관계를 수정할 수 있다
단점 특정 application 로직에 맞춰져있기 때문에 다른 application에 재사용하기 힘들다 중재자 패턴 사용 시 중재자 객체에 권한이 집중화되어 굉장히 크며 복잡해지므로, 설계 및 중재자 객체 수정 시 주의해야 한다
참조:
행동 패턴 – 중재자(Mediator)
– 참조: https://refactoring.guru/design-patterns/mediator
– 중재자(Mediator) 패턴
중재자 패턴은 객체들간의 무질서한 의존성을 줄여주는 행동 패턴이다. 이 패턴은 객체들간의 직접적인 통신을 제한하고, 중재자 객체를 통해서만 협력하도록 강제한다.
– 문제점
고객의 프로필을 만들고 수정하는 대화상자가 있다고 가정해보자. 이 대화상자에는 text 필드, 체크박스, 버튼 과 같은 다양한 요소가 있다. 웹서핑을 하다보면 form 요소들끼리 서로 연관있는 UI 를 본적이 있을것이다. 예를 들어 어떤 체크박스를 체크하면 인풋박스가 갑자기 나타나거나 저장버튼을 누르면 입력 필드에 대해서 Validation 메시지를 띄우기도 한다.
이런 로직의 코드가 form 요소안에 있으면 이런 요소의 클래스들은 다른 form 에서 재사용하기가 어려워진다. 예를 들어 위에서 언급한 체크박스 체크시 인풋박스를 보여주는 로직이 해당 체크박스 안에 있으면 이 체크박스를 다른 form 에서는 재사용할 수 없다.
– 해결책
중재자 패턴은 독립적으로 구성하고싶은 컴포넌트들간에 직접적인 통신을 막아준다. 대신 요청을 적절한 컴포넌트로 전달시키는 중재자 객체를 호출해서 간접적으로 소통해야 한다. 그렇게 되면 컴포넌트들내의 복잡한 의존관계가 아니라, 하나의 중재자 클래스에 대해서만 의존성을 가지게 된다.
프로필 수정 예제에서 대화상자 클래스가 중재자라고 할 수 있다. 대화상자 클래스는 모든 하위 요소들을 알고 있어서, 대화상자 클래스에 새로운 의존관계를 설정하지 않아도 된다.
제출 버튼이 있다고 가정해보자. 이전에는 유저가 제출 버튼을 클릭할 때, form 요소들 각각의 값에 대해서 유효성 체크를 해야만 했다. 하지만 지금은 click을 하면 대화상자에게 통보만 하면 된다. 대화상자는 자체적으로 유효성체크를 수행하거나, 해당 작업을 개별 요소들에게 전달한다. 제출 버튼은 form의 수많은 요소들에 엮여있지 않고, 대화상자 클래스 하나에만 의존하게 된다.
대화상자들의 모든 타입을 위한 공통 인터페이스를 추출하면 의존성을 더 줄일 수 있다. 공통 인터페이스에서는 모든 form 요소들에서 일어나는 이벤트를 대화상자에게 알릴 수 있는 메소드를 정의한다. 이렇게 구현하면 제출버튼은 해당 인터페이스를 구현하는 어떤 대화상자와도 동작할 수 있다.
이런 방법으로 중재자 패턴은 하나의 중재자 객체로 다양한 객체들 사이의 복잡한 관계망을 캡슐화한다. 의존관계가 덜 복잡한 클래스는 수정하기 쉬우며, 재사용하거나 확장도 훨씬 수월하다.
– 실생활 예제
공항 관제 구역에 접근하거나 출발하는 항공기안에 파일럿들은 서로 직접 통신하지 않는다. 대신 활주로 근처 타워안에 있는 항공 관제관과 통신한다. 항공 관제관이 없으면 파일럿들은 공항인근의 모든 비행기안에 있는 파일럿들과 통신해서 착륙 우선순위를 정해야 한다.
– 참여자
중재자 패턴의 동작구조와 참여자들을 알아보자.
Components(ComponentA~ComponentD): Component 들은 비즈니스 로직을 포함하는 클래스들이다. 각 Component 는 Mediator 인터페이스로 선언된 중재자를 참조하고 있다. Component 는 중재자의 실제 클래스는 알지 못하므로, 다른 중재자에 연결하여 재사용할 수도 있다.
Component 들은 비즈니스 로직을 포함하는 클래스들이다. 각 Component 는 Mediator 인터페이스로 선언된 중재자를 참조하고 있다. Component 는 중재자의 실제 클래스는 알지 못하므로, 다른 중재자에 연결하여 재사용할 수도 있다. Mediator(Mediator): Mediator 인터페이스는 component 들간의 소통을 위한 메소드를 정의하고 있는데, 대게 알림을 위한 단일 메소드를 정의하고 있다.
Mediator 인터페이스는 component 들간의 소통을 위한 메소드를 정의하고 있는데, 대게 알림을 위한 단일 메소드를 정의하고 있다. Concrete Mediator(ConcreteMediator): 다양한 Component 들간의 관계를 캡슐화 한다. 종종 Concrete Mediator 는 모든 Component 에 대한 참조를 가지고 있으면서, 가끔은 Component 들의 생명주기를 관리하기도 한다.
하나의 Component 는 다른 Component 에 대해서 알면 안 된다. 만약 Component 내부나 어떤 Component 에게 중요한 이벤트가 발생하면 중재자에게만 알려야 한다. 중재자는 알림을 받으면 sender를 식별할 수 있고, 어떤 Component 가 반응해야 하는지 판단할 수 있다.
Component의 관점에서 보면 마치 블랙박스와 같다고 할 수 있다. Sender 는 누가 요청을 다루게 될지 알 수 없고, Receiver는 최초에 누가 요청을 보냈는지 알 수 없다.
– 시나리오
이번 예제에서는 Mediator 패턴을 이용하여 다양한 버튼이나 체크박스, 텍스트 field와 같은 UI 클래스들간의 상호 의존관계를 제거해본다.
위 다이어그램은 Dialog 안에 Button, Textbox, Checkbox 의 요소들이 있는 상황을 다이어그램으로 표현한것이다. User 에 의해 이벤트가 일어난 요소는 다른 요소들과 직접적으로 통신하지 않는다. 대신 해당 요소는 중재자에게 해당 이벤트를 알려준다.
위 예제에서는 AuthenticationDialog 자체가 중재자가 된다. AuthenticationDialog 는 Button, Textbox, Checkbox 들이 어떻게 서로 협력해서 동작하는지 알고 있고, 간접적인 의사소통을 원활하게 해주고 있다. 이벤트 알림을 받으면 Dialog 는 어떤 요소가 이벤트를 처리해야하는지 그리고 호출을 적절하게 리다이렉팅 하는지 결정한다.
– Java 예제
예제를 통해 알아보자. 먼저 Mediator 부터 정의해보자. Mediator 는 notify 단일 메소드로 정의했다. Event를 발생시키는 요소 인자 sender와 어떤 이벤트인지에 대한 인자 event 를 선언하였다.
public interface Mediator { void notify(Component sender, String event); }
그 다음 Dialog 요소들의 부모 클래스인 Component를 정의한다. Mediator를 참조하는 중재자 dialog를 참조하고 있고, click이나 keypress 이벤트가 발생할 때 중재자에게 현재 자신의 객체 this와 발생한 이벤트를 넘기고 있다.
public class Component { protected Mediator dialog; public Component(Mediator dialog) { super(); this.dialog = dialog; } public void click() { dialog.notify(this, “click”); } public void keypress() { dialog.notify(this, “keypress”); } }
Component 의 세부클래스인 Button, Textbox, Checkbox를 정의해보자. Button과 Textbox는 Component 에서 정의한 click과 keypress 를 그대로 사용하면 된다.
Checkbox의 경우 약간 다르게 정의해보았는데, Checkbox는 현재 체크된 상태를 알려주는 메소드가 있어야 한다고 생각했다. 그리고 Checkbox 클릭시 중재자에게 notify를 할 때 “click” 과 별도로 “check” 이벤트를 전달해야 한다고 생각해서 중재자에게 “click” 이벤트를 공지하고 하였다. 그 다음 super.click() 을 호출한것은 ‘click” 이벤트도 전파되어야 하기 때문이라고 가정했다.
public class Button extends Component{ public Button(Mediator dialog) { super(dialog); } } public class Textbox extends Component { public Textbox(Mediator dialog) { super(dialog); } } public class Checkbox extends Component{ private boolean checked; public Checkbox(Mediator dialog) { super(dialog); checked = false; } public boolean checked() { return checked; } @Override public void click() { checked = !checked; dialog.notify(this, “check”); super.click(); } }
이제 AuthenticationDialog 클래스를 살펴보자. Dialog 안에는 많은 요소들이 있다. 이 글의 초반부에서 설명한것과 같이 만약 중재자 패턴이 아니었다면 isJoinForm 체크박스를 클릭할 때, 회원가입 요소들(regUsername, regPassword, regEmail)을 컨트롤 하므로, 다른 Dialog 에서 체크박스를 재사용하지 못했을것이다.
아래 코드에서 생성자를 눈여겨보자. 위의 클래스 다이어그램에서 각 요소들(Button, Textbox, Checkbox)은 중재자를 참조해야한다. AuthenticationDialog는 Mediator 인터페이스를 구현하는 중재자이다. 생성자에서 자기자신 this를 각 요소의 생성자함수에 넘겨줌으로써 중재자인 자신을 참조하도록 하고 있다.
Dialog 내의 모든 요소간 통신이나 제어는 notify 메소드에서 담당한다. ok 버튼을 누르거나 login 및 회원가입 form간 전환, ID 저장 기능은 각 해당 요소에서 제어하지 않는다.
public class AuthenticationDialog implements Mediator { public String title; public Checkbox isJoinForm; public Textbox loginUserName; public Textbox loginPassword; public Textbox regUsername; public Textbox regPassword; public Textbox regEmail; public Button ok; public Button cancel; public Checkbox remeberMe; public AuthenticationDialog() { super(); title = “Login”; isJoinForm = new Checkbox(this); loginUserName = new Textbox(this); loginPassword = new Textbox(this); regUsername = new Textbox(this); regPassword = new Textbox(this); regEmail = new Textbox(this); ok = new Button(this); cancel = new Button(this); remeberMe = new Checkbox(this); } public void printCurrentStatus() { System.out.println(“Title: ” + title); System.out.println(“isJoinForm: ” + isJoinForm.checked()); System.out.println(“remeberMe: ” + remeberMe.checked()); } @Override public void notify(Component sender, String event) { if(sender.equals(ok) && “click”.equals(event)) { if(isJoinForm.checked()) { System.out.println(“Validate [regUsername, regPassword, regEmail] elements”); System.out.println(“And user join this system.”); } else { System.out.println(“Login!”); } } else if(sender.equals(isJoinForm) && “check”.equals(event)) { if(isJoinForm.checked()) { title = “User Join Form”; System.out.println(“show [regUsername, regPassword, regEmail] elements”); } else { title = “Login”; System.out.println(“hide [regUsername, regPassword, regEmail] elements”); } } else if(sender.equals(remeberMe) && “check”.equals(event)) { if(remeberMe.checked()) { System.out.println(“set ID in cookie”); } else { System.out.println(“remove ID from cookie”); } } } }
중재자 패턴을 테스트하는 코드를 작성해보자. 시나리오는 다음과 같다.
Login 에서 회원가입 양식으로 전환하여 OK버튼(회원가입)을 클릭한 후, 다시 Login 양식으로 전환한다. 그리고 ID 기억하기 체크박스를 체크 한 후 Login을 하는 시나리오이다.
public static void main(String[] args) { AuthenticationDialog dialog = new AuthenticationDialog(); System.out.println(“==== 1.Current state”); dialog.printCurrentStatus(); System.out.println(); System.out.println(“==== 2. Convert from login to user join form”); dialog.isJoinForm.click(); System.out.println(); System.out.println(“==== 3. submit user join”); dialog.ok.click(); System.out.println(); System.out.println(“==== 4. Convert from user join to login”); dialog.isJoinForm.click(); System.out.println(); System.out.println(“==== 5. Check remember me”); dialog.remeberMe.click(); System.out.println(); System.out.println(“==== 6. Do login”); dialog.ok.click(); } ==== 1.Current state Title: Login isJoinForm: false remeberMe: false ==== 2. Convert from login to user join form show [regUsername, regPassword, regEmail] elements ==== 3. submit user join Validate [regUsername, regPassword, regEmail] elements And user join this system. ==== 4. Convert from user join to login hide [regUsername, regPassword, regEmail] elements ==== 5. Check remember me set ID in cookie ==== 6. Do login Login!
[디자인패턴] Mediator Pattern (중재자 패턴)
중재자 패턴의 목적과 사용이유
중재자 패턴이란
중재자 패턴 vs 옵저버 패턴
중재자 패턴의 예시
Related Patterns and Summary
중재자 패턴의 목적과 사용이유
Purpose
– 서로 상호작용하는 object들을 캡슐화함으로써 loose coupling을 유지하기 위해 사용한다.
Use When
– 객체들 사이에 너무 많은 관계가 얽혀있을때
– 객체들 사이의 상호작용 관계가 복잡할때
중재자 패턴이란
Mediator Pattern Diagram
M개의 object 사이에 N개의 관계가 형성되어 있어 아주 복잡하게 얽혀있을때 이를 M:1 관계로 바꿔주기 위해 중재자 패턴을 사용한다. M개의 object 사이에 이들의 관계를 control 하는 Mediator를 하나 넣어서 Mediator가 모든 object들의 communication을 관리하도록 한다.
objects들 사이에 Mediator를 넣어 연결관계를 캡슐화한다.
class들을 loose coupling 상태로 유지할 수 있다. (서로 알 필요 없고 Mediator가 모두 관리하므로)
장점 : 전체적인 연결관계를 이해하기 쉽다 (communication의 흐름을 이해하기 쉽다)
단점 : 특정 application 로직에 맞춰져있기 때문에 다른 application에 재사용하기 힘들다 (옵저버 패턴의 경우 반대이다. 재사용성은 좋지만 연결관계가 복잡해지면 이해하기 어렵다)
중재자 패턴 vs 옵저버 패턴
Observer Pattern Mediator Pattern
옵저버 패턴은 1개의 Publisher에 대해 N개의 Subscriber가 존재한다. 즉 복수의 Subscriber가 Publisher의 상태만 관찰하는 셈이다. 그러나 Mediator의 경우 M개의 Publisher와 n개의 Subscriber가 존재한다. 즉 M개의 Publisher가 서로서로 상태를 관찰하기 때문에 Publisher가 Subscriber가 될 수도, Subscriber가 Publisher가 될 수도 있다.
중재자 패턴의 예시
Font Dialog boxe
다음과 같이 Font box가 있을때 Font가 선택됨에 따라 지원되는 size, style, 등.. 이 다르다. 따라서 각 object들이 서로를 관찰하고 있어야 한다.
Mediator Pattern Diagram for Font Dialog
따라서 위의 다이어그램과 같이 Font box의 Mediator인 FontDialogDirector가 복수개의 Widget object들을 관리해줘야 한다.
Sequence Diagram for Font Dialog
1. ListBox가 Director에게 변화를 알려준다.
2. Director가 ListBox에서 어떤 selection이 선택된건지 요청해서 받아온다.
3. EntryField에게 그 selection을 전달한다.
4. 이제 EntryField는 그 selection에 맞는 style을 제공한다.
Related Patterns and Summary
Observer : 재사용성이 좋다. 복잡한 communication에서는 이해하기 힘들다. 1개의 Publisher와 N개의 Subscriber로 이루어져 있다.
Mediator : 재사용성이 안좋다. 복잡한 communication에서 이해하기 쉽다. M개의 Publisher, N개의 Subscriber 사이의 communication을 1개의 Mediator를 이용해 캡슐화하고 있다.
[Java][디자인 패턴] 19. 중재자 패턴 (Mediator Pattern)
반응형
디자인패턴
[Java][디자인 패턴] 19. 중재자 패턴 (Mediator Pattern)중재자 패턴은 분산된 다수의 객체 역할을 조정할 때 주로 사용한다.
중재자 패턴이란?
중재자 패턴은 객체의 관계를 하나의 객체로 정리하는 패턴이다.
중자재 패턴은 서로 의존적인 M:N 관계를 가진 객체를 느슨한 1:1 관계로 변경한다
복잡한 통신과 제어를 한 곳에 집중하여 처리하는 효과가 있다.
다른 동료 객체에 직접 접근해서 호출하지 않고 중재자를 의존해서 다른 동료 객체를 호출한다.
중재자 패턴은 객체의 강력한 구조적 결합 문제점을 해결한다.
중재자를 이용하지 않으면 다수의 동료 객체가 서로 정보를 직접 주고받는다. 중재자 패턴은 동료 객체끼리 정보를 직접 주고받지 않도록 통신 경로를 제한한다.
중재자는 하나의 객체 요청에 대해 모든 객체로 통보를 처리해야 하므로 경로의 수가 증가한다.
중재자 패턴을 설계할 때는 경로의 수가 증가함에 따라 성능이 저하되지 않도록 신경써서 구성해야 한다.
중재자 패턴 구조
Mediator 동료 간 통신을 위한 인터페이스
Collegue 동료 간에 전달되는 이벤트를 정의하는 추상 클래스
ConcreteMedediator Colleague 객체를 조정하여 협동 조작을 구현하고 동료를 유지 관리
ConcreteColleague 다른 Colleague가 생성한 Mediator를 통해 받은 알림 작업을 구현
중재자 패턴 코드
1. Mediator 인터페이스
public interface Mediator { void addColleague(Colleague colleague); void mediate(Colleague colleague); }
2. ColleagueType enum
public enum ColleagueType { USER, SYSTEM, ADMIN }
3. Colleague 추상 클래스
public abstract class Colleague { private Mediator mediator; private String message; private final String name; private final ColleagueType type; protected Colleague(String name, ColleagueType type) { this.name = name; this.type = type; } public void setMediator(Mediator mediator) { this.mediator = mediator; } public void setMessage(String message) { this.message = message; } public Mediator getMediator() { return mediator; } public String getMessage() { return message; } public String getName() { return name; } public ColleagueType getType() { return type; } public void send() { System.out.println(this.name + ” send()”); System.out.println(); mediator.mediate(this); } public abstract void receive(Colleague colleague); }
4. Colleague 구체 클래스
public class UserConcreteColleague extends Colleague { public UserConcreteColleague(String name) { super(name, ColleagueType.USER); } @Override public void receive(Colleague colleague) { if (ColleagueType.SYSTEM == colleague.getType()) { System.out.print(“[SYSTEM] “); } else if (ColleagueType.USER == colleague.getType()) { System.out.print(“[” + colleague.getName() + “] “); } System.out.println(colleague.getMessage()); } }
public class SystemConcreteColleague extends Colleague { public SystemConcreteColleague(String name) { super(name, ColleagueType.SYSTEM); } @Override public void receive(Colleague colleague) { System.out.println(“System can’t receive messages”); } }
public class AdminConcreteColleague extends Colleague { public AdminConcreteColleague(String name) { super(name, ColleagueType.ADMIN); } @Override public void receive(Colleague colleague) { System.out.println(“Admin can’t receive messages”); } }
5. Mediator 테스트 코드
class MediatorTest { @Test @DisplayName(“Mediator 테스트”) void mediatorTest() { Mediator mediator = new ConcreteMediator(); Colleague colleagueUser1 = new UserConcreteColleague(“User1”); Colleague colleagueUser2 = new UserConcreteColleague(“User2”); Colleague colleagueSystem = new SystemConcreteColleague(“System”); Colleague colleagueAdmin = new AdminConcreteColleague(“Admin”); colleagueUser1.setMediator(mediator); colleagueUser2.setMediator(mediator); colleagueSystem.setMediator(mediator); colleagueAdmin.setMediator(mediator); mediator.addColleague(colleagueUser1); mediator.addColleague(colleagueUser2); mediator.addColleague(colleagueSystem); mediator.addColleague(colleagueAdmin); colleagueUser1.setMessage(“안녕하세요. User1이 보낸 메시지 입니다.”); colleagueUser1.send(); colleagueUser2.setMessage(“안녕하세요. User2가 보낸 메시지 입니다.”); colleagueUser2.send(); colleagueSystem.setMessage(“잠시 후 20분 뒤에 점검이 있습니다.”); colleagueSystem.send(); } }
중재자 패턴의 특징
양방향
중재자 패턴은 다른 패턴들과 달리 양방향 통신을 처리한다. concreteColleague에서 중재자로 데이터 전송 메시지를 전달 받은 동료 갹체는 수신한 메시지를 다시 중개 객체로 전송 전송 받은 중개 객체는 동작을 분석한 후 처리 의무가 있는 다른 동료 객체에게 행위를 요청 중재자 패턴은 Mediator와 Colleague 사이를 양방향 통신하면서 요청한 행위를 조정
Github 코드
Github 예제 코드 링크
Github 예제 테스트 코드 링크
참고 자료
반응형
중재자 패턴(Mediator)
반응형
중재자 패턴(Mediator)은 행위(Behavioral) 패턴 중 하나로써 수많은 객체들 간의 복잡한 상호작용을 캡슐화하여 객체로 정의하는 패턴이다.
중재자 의미를 생각하면 쉽다. 객체끼리 서로 직접 통신하지 않고 중재자에게 전달하면 이를 전달해 주는 방식으로 통신하기 때문에 객체 간 의존성을 줄일 수 있으므로 결합도를 감소시킬 수 있다.
중재자 패턴의 구조는 다음과 같다.
Mediator : Colleague 객체 간의 통신을 중재자 역할을 통해 관리하는 인터페이스이다. Colleague 객체들은 전달 사항이 생기면 Mediator에게 전달한다.
: Colleague 객체 간의 통신을 중재자 역할을 통해 관리하는 인터페이스이다. Colleague 객체들은 전달 사항이 생기면 Mediator에게 전달한다. ConcreteMediator : Mediator를 구현한 클래스
: Mediator를 구현한 클래스 Colleague : 서로 통신할 객체의 인터페이스, Mediator에게 전달사항을 전달
: 서로 통신할 객체의 인터페이스, Mediator에게 전달사항을 전달 Colleague1, Colleauge2 : 객체를 구현한 클래스, 통신 내용을 Mediator에게 전달받는다.
간단한 예시를 통해 중재자 패턴을 알아보자.
A, B, C라는 사람이 약속을 정하기 위해 통신하는 과정을 생각해 보자.
요즘에야 카카오톡 같은 단체 메신저 시스템이 존재하지만 이런 시스템이 없던 시절에는 하나하나씩 문자메시지를 통해 전달해야 했다.
이런 시스템은 A가 메시지를 공유하기 위해서는 B, C 모두에게 전달해야 하는 번거로움이 존재한다.
하지만 요즘에는 카카오톡 같은 단체 메신저 시스템을 이용하면 한 개의 메시지만 전달하여도 카카오톡 서버가 알아서 채팅방에 속한 사람들에게 전달해 준다.
즉, 카카오톡 채팅방이 중재자 역할을 수행해 주는 것이다. 그렇다면 중재자 패턴을 적용하여 위의 상황을 구현해보자.
먼저 Mediator이다. Colleague들을 관리해 줄 List를 하나 가지며 setColleague() 메서드를 통해 Colleague들을 List에 추가해 준다.
어떻게 중재할 것인지에 대해선 추상 메서드로 구현하여 넘겨준다.
import java.util.ArrayList; import java.util.List; public abstract class Mediator { protected List
colleagues; public Mediator() { colleagues = new ArrayList<>(); } public void setColleague(Colleague colleague) { colleagues.add(colleague); } public abstract void mediate(String msg); } 다음으로 중재자 역할인 카카오톡을 구현한 KaKaoTalk이다. meidate() 메서드를 구현하여 Colleague들을 중재해 준다.
public class KaKaoTalk extends Mediator { @Override public void mediate(String msg) { for (Colleague colleague : colleagues) { colleague.action(msg); } } }
다음으로 Colleague이다. Mediator를 하나 가지며 자신을 Mediator에게 등록해 주는 setMediator() 메서드와 메시지를 전달하는 sendMsg() 메서드를 가진다.
중재자가 메시지를 전달할 때 어떻게 반응할 것인지는 추상 메서드로 넘겨준다.
public abstract class Colleague { private Mediator mediator; public void setMediator(Mediator mediator) { this.mediator = mediator; mediator.setColleague(this); } public void sendMsg(String msg) { mediator.mediate(msg); } public abstract void action(String msg); }
마지막으로 카카오톡 채팅방 유저를 구현한 KaKaoTalkColleague이다. action() 메서드를 구현해 준다.
public class KaKaoTalkColleague extends Colleague { @Override public void action(String msg) { System.out.println(“Send a [” + msg + “] to ” + this); } }
Main 클래스에서 A, B, C 유저를 카카오톡 채팅방에 등록한 후 A가 메시지를 전송하면 중재자인 카카오톡 서버가 B와 C에게 해당 메시지를 전달해 주는 것을 알 수 있다.
public class Main { public static void main(String[] args) { Mediator kakaoTalk = new KaKaoTalk(); Colleague colleagueA = new KaKaoTalkColleague(); Colleague colleagueB = new KaKaoTalkColleague(); Colleague colleagueC = new KaKaoTalkColleague(); colleagueA.setMediator(kakaoTalk); colleagueB.setMediator(kakaoTalk); colleagueC.setMediator(kakaoTalk); colleagueA.sendMsg(“내일 8시에 만나자”); } }
반응형
17. 중재자 패턴 (Mediator pattern)
중재자 패턴
여러 객체들이 소통하는 방법을 캡슐화하는 패턴
–> 여러 컴포넌트간의 결합도를 중재자를 통해 낮출 수 있다.
ex) 비행기들은 관제탑이라는 Mediator를 통해 서로 소통한다.
코드로 알아보기
호텔과 호텔의 여러 서비스들에 대한 코드가 있다고 해보자.
main에서 손님(guest)이 타월을 달라고 요청하고, 식사를 하려한다.
그리고 식당(resturant)이 청소를 요청한다.
현재 guest는 resturant과 cleaningService를 aggregate.
gym은 cleaningService를 aggregate
resturant은 cleaningService를 aggregate
❗️문제점❗️
각 클래스들을 보면 서로 의존관계를 얽히고 섥히게 가지고 있는 것을 볼 수 있다 . 만약 BreakFast 클래스를 새로 만든다면 Restarant클래스를 extends 또는 aggregate할 것이다. 하지만 그렇게 되면 BreakFast 클래스는 CleaningService역시 aggregate하게 된다.
특히 Guest가 다양한 서비스에 대해서 구체적으로 알아야 한다.
이렇게 다양한 클래스들이 엮이게 되는 상황에서 중재자 패턴을 적용해보자.
먼저 Guest 클래스를 보자. (CollegueA)
Guest는 FrontDesk를 가지고 있는데, Cleaning서비스, Resturant서비스 등 모든 서비스를 중재자인 FrontDesk를 통해 하는 것이다.
중재자인 FrontDesk (Mediator)
FrontDesk는 중재자로써 모든 서비스들을 알고 있어도 된다. Guest가 요청한 서비스를 각 서비스들에게 전달한다.
CleaningService (CollegueB)
Restaurant (CollegueC)
그리고 위의 Resturant 역시 clean서비스가 필요하다면 직접 CleaningService에게 요청하는 것이 아니라 FrontDesk를 통해 요청하고 있다.
장점과 단점
장점
1. 컴포넌트 코드를 변경하지 않고 새로운 중재자를 만들어 사용할 수 있다.
2. 각각의 컴포넌트 코드를 보다 간결하게 유지할 수 있다.
단점
중재자 역할을 하는 클래스의 복잡도와 결합도가 증가한다. 의존성이 한 곳으로 몰린다.
실제로 어디에서 사용되나?
1. 자바의 ExcutorService, Executor
2. 스프링MVC의 DispatcherService
스프링MVC의 디스패처 서블릿은 다양한 핸들러, 어댑터들을 가지고 이들을 이어준다.
출처: 인프런 백기선님 ‘코딩으로 학습하는 GoF 강의’
https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4
[디자인패턴][Mediator] 중재자 패턴
반응형
중재자 패턴 정의
클래스 간의 복잡한 관계들을 캡슐화하여 하나의 클래스에서 관리하도록 처리하는 패턴
M개의 객체들 사이에 중재자를 추가하여 중재자가 모든 객체들의 통신을 담당
각 객체들은 서로 알 필요가 없고 중재자 클래스가 관리하므로 loose coupling을 유지
옵저버 패턴은 1개의 publisher(subject)가 N개의 subscriber(observer)에 대해서 push하는 방식을 통해 관리하지만 중재자 패턴은 M개의 publisher와 N개의 subscriber 사이에서 1개의 중재자(mediator)를 통해서 통신하는 방식
Mediator 패턴 예시, 출처 – https://refactoring.guru/design-patterns/mediator
중재자 패턴은
복잡한 M개의 객체 사이에 N개의 관계가 형성되어 있을 때
M개의 객체 사이에 중재자를 하나 넣어서
이를 M:1 관계로 바꿔준다.
중재자 패턴 언제 사용?
객체들 사이에 너무 많은 관계가 맺어져 있을 때
객체들 사이에 상호작용 관계가 복잡할 때
중재자 패턴 적용 전 (M:N 관계) 중재자 패턴 적용 후 (M:1 관계)
중재자 패턴 클래스 다이어그램
Mediator 패턴 Class Diagram
중재자 패턴 활용
메세지 전송(채팅 프로그램)을 중재파 패턴을 적용한 예시입니다.
from abc import ABC, abstractmethod class Mediator(ABC): @abstractmethod def add_user(self, user): “”” 사용자 추가 “”” pass @abstractmethod def del_user(self, user): “”” 사용자 삭제 “”” pass @abstractmethod def send_message(self, message, user): “”” 메세지 전송 “”” pass class ConcreteMediator(Mediator): def __init__(self): self.users = [] def add_user(self, user): self.users.append(user) def del_user(self, user): if user in self.users: self.users.remove(user) def send_message(self, message, from_user): “”” 메시지 보낸 사람을 제외하고 메시지 전송 “”” for user in self.users: if from_user != user: user.receive(message) class Colleague(ABC): def __init__(self, mediator, name): self.mediator = mediator self.name = name @abstractmethod def send(self, message): pass @abstractmethod def receive(self, message): pass class ConcreteColleague(Colleague): def __init__(self, mediator, name): self.mediator = mediator self.name = name def send(self, message): print(f'{self.name}, send message : {message}’) self.mediator.send_message(message, self) def receive(self, message): print(f'{self.name}, received message : {message}’) mediator = ConcreteMediator() user1 = ConcreteColleague(mediator, ‘james’) user2 = ConcreteColleague(mediator, ‘kebin’) user3 = ConcreteColleague(mediator, ‘taylor’) mediator.add_user(user1) mediator.add_user(user2) mediator.add_user(user3) user1.send(‘hello’) user2.send(‘nice to meet you’) user3.send(‘great!’)
출력
james, send message : hello kebin, received message : hello taylor, received message : hello kebin, send message : nice to meet you james, received message : nice to meet you taylor, received message : nice to meet you taylor, send message : great! james, received message : great! kebin, received message : great!
참고 자료
https://sourcemaking.com/design_patterns/mediator
https://en.proft.me/2017/02/17/mediator-pattern-java-and-python/
https://effectiveprogramming.tistory.com/entry/Mediator-%ED%8C%A8%ED%84%B4
https://medium.com/flutter-community/flutter-design-patterns-22-mediator-575e7aa6bfa9
https://brownbears.tistory.com/568
반응형
키워드에 대한 정보 중재자 패턴
다음은 Bing에서 중재자 패턴 주제에 대한 검색 결과입니다. 필요한 경우 더 읽을 수 있습니다.
이 기사는 인터넷의 다양한 출처에서 편집되었습니다. 이 기사가 유용했기를 바랍니다. 이 기사가 유용하다고 생각되면 공유하십시오. 매우 감사합니다!
사람들이 주제에 대해 자주 검색하는 키워드 GoF의 Design Pattern – 12. Mediator
- 동영상
- 공유
- 카메라폰
- 동영상폰
- 무료
- 올리기
GoF의 #Design #Pattern #- #12. #Mediator
YouTube에서 중재자 패턴 주제의 다른 동영상 보기
주제에 대한 기사를 시청해 주셔서 감사합니다 GoF의 Design Pattern – 12. Mediator | 중재자 패턴, 이 기사가 유용하다고 생각되면 공유하십시오, 매우 감사합니다.