옵저버 패턴(observer pattern)은 주체가 어떤 객체(subject)의 상태 변화를 관찰하다가 상태 변화가 있을 때마다 메서드 등을 통해 옵저버 목록에 있는 옵저버들에게 변화를 알려주는 디자인 패턴
👉 주체란 객체의 상태 변화를 보고 있는 관찰자.
👉 옵저버들이란 이 객체의 상태 변화에 따라 전달되는 메서드 등을 기반으로 '추가 변화 사항'이 생기는 객체들
📍 예시 1.
내가 어떤 사람인 주체를 '팔로우'했다면 주체가 포스팅을 올리게 되면 알림이 '팔로워'(옵저버) 에게 간다.
import java.util.ArrayList;
import java.util.List;
interface Subject {
public void register(Observer obj);
public void unregister(Observer obj);
public void notifyObservers();
public Object getUpdate(Observer obj);
}
interface Observer {
public void update();
}
class Topic implements Subject {
private List<Observer> observers;
private String message;
public Topic() {
this.observers = new ArrayList<>();
this.message = "";
}
@Override
public void register(Observer obj) {
if (!observers.contains(obj)) observers.add(obj);
}
@Override
public void unregister(Observer obj) {
observers.remove(obj);
}
@Override
public void notifyObservers() {
this.observers.forEach(Observer::update);
}
@Override
public Object getUpdate(Observer obj) {
return this.message;
}
public void postMessage(String msg) {
System.out.println("Message sended to Topic: " + msg);
this.message = msg;
notifyObservers();
}
}
class TopicSubscriber implements Observer {
private String name;
private Subject topic;
public TopicSubscriber(String name, Subject topic) {
this.name = name;
this.topic = topic;
}
@Override
public void update() {
String msg = (String) topic.getUpdate(this);
System.out.println(name + ":: got message >> " + msg);
}
}
public class HelloWorld {
public static void main(String[] args) {
Topic topic = new Topic();
Observer a = new TopicSubscriber("a", topic);
Observer b = new TopicSubscriber("b", topic);
Observer c = new TopicSubscriber("c", topic);
topic.register(a);
topic.register(b);
topic.register(c);
topic.postMessage("amumu is op champion!!");
}
}
/*
Message sended to Topic: amumu is op champion!!
a:: got message >> amumu is op champion!!
b:: got message >> amumu is op champion!!
c:: got message >> amumu is op champion!!
*/
📍 예시 2.
MVC(Model-View-Controller) 패턴에도 사용된다. 주체라고 볼 수 있는 모델(model)에서 변경 사항이 생겨 update()메서드로 옵저버인 뷰에 알려주고 이를 기반으로 컨트롤러(controller) 등이 작동하는 것이다.
프록시 패턴 : 대상 객체(subject)에 접근하기 전 그 접근에 대한 흐름을 가로채 대상 객체 앞단의 인터페이스 역할을 하는 디자인 패턴
👉 흐름을 바꾸는 패턴
👉 객체의 속성, 변환 등을 보완하여 보안, 데이터 검증, 캐싱, 로깅에 사용한다. 프록시 서버가 대표적인 예이다.
✅ 프록시 서버
서버와 클라이언트 사이에서 클라이언트가 자신을 통해 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해주는 컴퓨터 시스템이나 응용 프로그램을 가르킨다.
프록시 서버로 쓰는 CloudFlare
: CloudFlare는 전세계적으로 분산된 서버가 있고 이를 통해 어떠한 시스템의 콘텐츠 전달을 빠르게 할 수 있는 CDN 서비스이다. 사용자, 크롤러, 공격자가 자신의 웹 사이트에 접속하게 될텐데, 이때 CloudFlare를 통해 공격자로부터 보호할 수 있다. (DDOS - 짧은 기간 동안 네트워크에 많은 요청을 보내 네트워크를 마비시켜 웹 사이트의 가용성을 방 공격으로부터 보호)
CORS와 프론트엔드의 프록시 서버
: CORS(Cross-Origin Resource Sharing)는 서버가 웹 브라우저에서 리소스를 로드할 때 다른 오리진을 통해 로드하지 못하게 하는 HTTP 헤더 기반 메커니즘
❓ 오리진 : 프로토콜과 호스트 이름, 포트의 조합. 예를 들어, https://kundol.com:12010/test 라는 주소에서 오리진은 https://kundol.com:12010
: 프론트엔드 개발 시 프론트엔드 서버를 만들어서 백엔드 서버와 통신할 떄 주로 CORS 에러를 마주치는데, 이를 해결하기 위해 프론트엔드에서 프록시 서버를 만든다.
📍 프록시 서버 예시.
unction createReactiveObject(target, callback) {
const proxy = new Proxy(target, {
set(obj, prop, value){
if(value !== obj[prop]){
const prev = obj[prop]
obj[prop] = value
callback(`${prop}가 [${prev}] >> [${value}] 로 변경되었습니다`)
}
return true
}
})
return proxy
}
const a = {
"형규" : "솔로"
}
const b = createReactiveObject(a, console.log)
b.형규 = "솔로"
b.형규 = "커플"
// 형규가 [솔로] >> [커플] 로 변경되었습니다
출처: [책]면접을 위한 CS 전공지식 노트