Notice
Recent Posts
Recent Comments
Link
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

엘라의 개발 스케치 Note

[CS 전공지식 노트] 1.1.4 옵저버 패턴 본문

CS/면접을 위한 CS 전공지식 노트

[CS 전공지식 노트] 1.1.4 옵저버 패턴

엘라랑이 2024. 3. 8. 15:55

# 옵저버 패턴

더보기

 

? 옵저버 패턴

- 주체가 어떤 객체의 상태 변화를 관찰하다가 상태 변화가 있을 때마다 메서드 등을 통해 옵저버 목록에 있는 옵저버들에게 변화를 알려주는 디자인 패턴
  • 주체
    • 객체의 상태 변화를 보고 있는 관찰자
  • 옵저버
    • 이 객체의 상태 변화에 따라 전달되는 메서드 등을 기반으로 '추가 변화 사항'이 생기는 객체들
  • 객체 / 주체 분리 옵저버 패턴

 

  • 객체 - 주체 합체 옵저버 패턴

 

  • 옵저버 패턴 활용 서비스 예시 - 트위터

 

 

  • 옵저버 패턴은 주로 이벤트 기반 시스템에서 사용
    • MVC 패턴에도 사용됨
      • 모델(주체) -> 변경사항 update() -> 뷰(옵저버) -> 컨트롤러 등 작동

 

 

 

! 자바에서의 옵저버 패턴

더보기

 

  • topic(주체이자 객체) 기반 옵저버 패턴 구현
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!!
*/

 

※ 자바: 상속과 구현

  • 상속(extends): 일반 클래스, abstract 클래스 기반 구현
    • 자식 클래스가 부모 클래스의 메서드 등을 상속받아 사용
    • 자식 클래스에서 추가 및 확장 가능
    • 재사용성, 중복성의 최소화
  • 구현(implements): 인터페이스 기반 구현
    • 부모 인터페이스(interface)를 자식 클래스에서 재정의하여 구현하는 것
    • 반드시 부모 클래스의 메서드를 재정의하여 구현

 

! 자바스크립트에서의 옵저버 패턴

더보기

 

  • 프록시 객체?
    • 어떠한 대상의 기본적인 동작(속성 접근, 할당, 순회, 열거, 함수 호출 등)의 작업을 가로챌 수 있는 객체
    • 자바스크립트에서의 프록시 객체 -> 두 개의 매개변수
      • target: 프록시할 대상
      • handler: target 동작을 가로채고 어떠한 동작을 할 것인지가 설정되어 있는 함수
const handler = {
	get: function(target, name) {
    	return name === 'name' ? `${target.a} ${target.b}` : target[name]
    }
}
const p = new Proxy({a: 'KUNDOL', b: 'IS AUMUMU ZANGIN'}, handler}
console.log(p.name) // KUNDOL IS AUMUMU ZANGIN

 

  • 프록시 객체를 이용한 옵저버 패턴
function 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.형규 = "커플"
// 형규가 [솔로] >> [커플] 로 변경되었습니다

 

! Vue.js 3.0의 옵저버 패턴

더보기

 

  • 프록시 객체를 이용한 옵저버 패턴
    • Vue.js 3.0에서 ref나 reactice로 정의 -> 해당값 변경 -> 자동으로 DOM에 있는 값 변경
      • DOM(Document Object Model)
        • 문서 객체 모델. 웹 브라우저상의 화면을 이루고 있는 요소들
function createReactiveObject{
	target: Target,
    isReadonly: boolean,
    baseHandlers: ProxyHandler<any>,
    collectionHandlers: ProxyHandler<any>,
    proxyMap: WeakMap<Target, any> // 프록시 객체
) {
	if (!isObject(target)) {
    	if (__DEV__) {
        	console.warn(`value cannot be made reactive: ${String(target)}`)
        }
        return target
    }
    // target is already a Proxy, return it.
    // exception: calling readonly() on a reactive object
    if (
    	target[ReactiveFlags.RAW] &&
        !(isReadonly && target[ReactiveFlags.IS_REACTIVE])
    ) {
        return target
    }
    // target already has corresponding Proxy
    const existingProxy = proxyMap.get(target)
    if (existingProxy) {
        return existingProxy
    }
	// only a whitelist of value types can be observed.
    const targetType = getTargetType(target)
    if (targetType === targetType.INVALID) {
    	return target
    }
    const proxy = new Proxy(
    	target,
        targetType === targetType.COLLECTION ? collectionHandlers :
baseHandlers
	)
    proxyMap.set(target, proxy)
    return proxy
}
Comments