티스토리 뷰
728x90
1. 옵저버 패턴?
- 다수의 객체가 특정 객체 상태 변화를 감지하고 알림을 받는 패턴
- 발행 publish 구독 subscribe 패턴을 구현
- subject > 여러 옵저버들을 등록, 해지 기능 제공
- 클라이언트는 서브젝트에 옵저버 등록, 서브젝트의 상태 변경
- 서브젝트는 상태가 변경되면 자신에게 등록된 모든 옵저버를 순회하면서 옵저버가 제공하는 메소드 호출
- observer > interface
- observer가 해야할 일, 규약
- concrete observer > observer 구현체
2. 적용하기
- 간단한 채팅 소스로 예시 작성
2.1. 적용전
- 주체가 주기적으로 요청해서 가져옴.
public class ChatServer {
private Map<String, List<String>> messages;
public ChatServer() {
this.messages = new HashMap<>();
}
public void add(String subject, String message) {
if (messages.containsKey(subject)) {
messages.get(subject).add(message);
} else {
List<String> messageList = new ArrayList<>();
messageList.add(message);
messages.put(subject, messageList);
}
}
public List<String> getMessage(String subject) {
return messages.get(subject);
}
}
public class User {
private ChatServer chatServer;
public User(ChatServer chatServer) {
this.chatServer = chatServer;
}
public void sendMessage(String subject, String message) {
chatServer.add(subject, message);
}
public List<String> getMessage(String subject) {
return chatServer.getMessage(subject);
}
}
ChatServer chatServer = new ChatServer();
User user1 = new User(chatServer);
user1.sendMessage("디자인패턴", "이번엔 옵저버 패턴입니다.");
user1.sendMessage("롤드컵2021", "LCK 화이팅!");
User user2 = new User(chatServer);
System.out.println(user2.getMessage("디자인패턴"));
user1.sendMessage("디자인패턴", "예제 코드 보는 중..");
System.out.println(user2.getMessage("디자인패턴"));
2.2. 패턴 적용 후
- subject → ChatServer
- observer → Subscriber
- concrete observer → User
public interface Subscriber {
void handleMessage(String message);
}
public class User implements Subscriber {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public void handleMessage(String message) {
System.out.println(message);
}
}
public class ChatServer {
private Map<String, List<Subscriber>> subscribers = new HashMap<>();
public void register(String subject, Subscriber subscriber) {
if (this.subscribers.containsKey(subject)) {
this.subscribers.get(subject).add(subscriber);
} else {
List<Subscriber> list = new ArrayList<>();
list.add(subscriber);
this.subscribers.put(subject, list);
}
}
public void unregister(String subject, Subscriber subscriber) {
if (this.subscribers.containsKey(subject)) {
this.subscribers.get(subject).remove(subscriber);
}
}
public void sendMessage(User user, String subject, String message) {
if (this.subscribers.containsKey(subject)) {
String userMessage = user.getName() + ": " + message;
this.subscribers.get(subject).forEach(s -> s.handleMessage(userMessage));
}
}
}
ChatServer chatServer = new ChatServer();
User user1 = new User(chatServer);
user1.sendMessage("디자인패턴", "이번엔 옵저버 패턴입니다.");
user1.sendMessage("롤드컵2021", "LCK 화이팅!");
User user2 = new User(chatServer);
System.out.println(user2.getMessage("디자인패턴"));
user1.sendMessage("디자인패턴", "예제 코드 보는 중..");
System.out.println(user2.getMessage("디자인패턴"));
3. 장점과 단점
3.1. 장점
- 상태를 변경하는 객체 publisher 와 변경을 감지하는 객체 subsriber 의 관계를 느슨하게 유지할 수 있다.
- subject의 상태 변경을 주기적으로 조회하지 않고 자동으로 감지할 수 있다.
- 런타임에 옵저버를 추가하거나 제거할 수 있다.
3.2. 단점
- 복잡도가 증가한다.
- 다수 observer 객체를 등록 이후 해지 않는다면 memory leak이 발생할 수도 있다.
- map에 옵저버가 등록되어있어 gc 대상에서 제외됨.
위글은 인프런의 코딩으로 학습하는 GoF의 디자인 패턴강의를 정리하였습니다.
백기선님의 수락으로 정리하였으며 더 자세한 내용은 강의를 수강하시기 바랍니다.
https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4/dashboard
728x90
'디자인 패턴' 카테고리의 다른 글
21. 전략 패턴 (0) | 2022.02.11 |
---|---|
20. 상태(State) 패턴 (0) | 2022.02.11 |
18. 메멘토 패턴 (0) | 2022.02.10 |
17. 중재자 패턴 (0) | 2022.02.10 |
16. 이터레이터 패턴 (0) | 2022.02.10 |
댓글