Home > CS > 2024 > πŸ’Ύ [CS] μ˜΅μ €λ²„ νŒ¨ν„΄(Observer pattern)

πŸ’Ύ [CS] μ˜΅μ €λ²„ νŒ¨ν„΄(Observer pattern)
CS

πŸ’Ύ [CS] μ˜΅μ €λ²„ νŒ¨ν„΄(Observer pattern).

  • μ˜΅μ €λ²„ νŒ¨ν„΄(observer pattern)은 주체가 μ–΄λ–€ 객체(subject)의 μƒνƒœ λ³€ν™”λ₯Ό κ΄€μ°°ν•˜λ‹€κ°€ μƒνƒœ λ³€ν™”κ°€ μžˆμ„ λ•Œλ§ˆλ‹€ λ©”μ„œλ“œ 등을 톡해 μ˜΅μ €λ²„ λͺ©λ‘μ— μžˆλŠ” μ˜΅μ €λ²„λ“€μ—κ²Œ λ³€ν™”λ₯Ό μ•Œλ €μ£ΌλŠ” λ””μžμΈ νŒ¨ν„΄μž…λ‹ˆλ‹€.

  • μ—¬κΈ°μ„œ μ£Όμ²΄λž€ 객체의 μƒνƒœ λ³€ν™”λ₯Ό 보고 μžˆλŠ” κ΄€μ°°μžμ΄λ©°, μ˜΅μ €λ²„λ“€μ΄λž€ 이 객체의 μƒνƒœ 변화에 따라 μ „λ‹¬λ˜λŠ” λ©”μ„œλ“œ 등을 기반으둜 β€˜μΆ”κ°€ λ³€ν™” 사항’이 μƒκΈ°λŠ” 객체듀을 μ˜λ―Έν•©λ‹ˆλ‹€.

  • λ˜ν•œ, μœ„μ˜ 그림처럼 주체와 객체λ₯Ό λ”°λ‘œ 두지 μ•Šκ³  μƒνƒœκ°€ λ³€κ²½λ˜λŠ” 객체λ₯Ό 기반으둜 κ΅¬μΆ•ν•˜κΈ°λ„ ν•©λ‹ˆλ‹€.
  • μ˜΅μ €λ²„ νŒ¨ν„΄μ„ ν™œμš©ν•œ μ„œλΉ„μŠ€λ‘œλŠ” νŠΈμœ„ν„°κ°€ μžˆμŠ΅λ‹ˆλ‹€.

  • μœ„μ˜ 그림처럼 λ‚΄κ°€ μ–΄λ–€ μ‚¬λžŒμΈ 주체λ₯Ό β€˜νŒ”λ‘œμš°β€™ ν–ˆλ‹€λ©΄ 주체가 ν¬μŠ€νŒ…μ„ 올리게 되면 μ•Œλ¦Όμ΄ β€˜νŒ”λ‘œμ›Œβ€™μ—κ²Œ κ°€μ•Όν•©λ‹ˆλ‹€.

  • λ˜ν•œ, μ˜΅μ €λ²„ νŒ¨ν„΄μ€ 주둜 이벀트 기반 μ‹œμŠ€ν…œμ— μ‚¬μš©ν•˜λ©° MVC(Model-View-Controller) νŒ¨ν„΄μ—λ„ μ‚¬μš©λ©λ‹ˆλ‹€.
    • 예λ₯Ό λ“€μ–΄ 주체라고 λ³Ό 수 μžˆλŠ” λͺ¨λΈ(model)μ—μ„œ λ³€κ²½ 사항이 생겨 update() λ©”μ„œλ“œλ‘œ μ˜΅μ €λ²„μΈ 뷰에 μ•Œλ €μ£Όκ³  이λ₯Ό 기반으둜 컨트둀러(controller) 등이 μž‘λ™ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

1️⃣ μžλ°”μ—μ„œμ˜ μ˜΅μ €λ²„ νŒ¨ν„΄.

// Observer
public interface Observer {
    void update();
}

// Subject
public interface Subject {
    void register(Observer obj);
    void unregister(Observer obj);
    void notifyObservers();
    Object getUpdate(Observer obj);
}

// Topic
import java.util.ArrayList;
import java.util.List;

public 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();
    }
}

// TopicSubscriber
public 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);
	}
}

// Main
public class Main {

	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("nice to meet you");
	}
}

μ‹€ν–‰ κ²°κ³Ό

Message sended to Topic: nice to meet you
a:: got message >> nice to meet you
b:: got message >> nice to meet you
c:: got message >> nice to meet you
  • topic을 기반으둜 μ˜΅μ €λ²„ νŒ¨ν„΄μ„ κ΅¬ν˜„ν–ˆμŠ΅λ‹ˆλ‹€.
    • μ—¬κΈ°μ„œ topic은 주체이자 객체가 λ©λ‹ˆλ‹€.
      • class Topic implements Subjectλ₯Ό 톡해 Subject interfaceλ₯Ό κ΅¬ν˜„ν–ˆκ³  Observer a = new TopicSubscriber("a", topic); 으둜 μ˜΅μ €λ²„λ₯Ό μ„ μ–Έν•  λ•Œ ν•΄λ‹Ή 이름과 μ–΄λ– ν•œ ν† ν”½μ˜ μ˜΅μ €λ²„κ°€ 될 것인지λ₯Ό μ •ν–ˆμŠ΅λ‹ˆλ‹€.

μžλ°”: 상속과 κ΅¬ν˜„

  • μœ„μ˜ μ½”λ“œμ— λ‚˜μ˜¨ implements λ“± μžλ°”μ˜ 상속과 κ΅¬ν˜„μ˜ νŠΉμ§•κ³Ό 차이에 λŒ€ν•΄ μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€.
    • 상속(extends)
      • μžμ‹ ν΄λž˜μŠ€κ°€ λΆ€λͺ¨ 클래슀의 λ©”μ„œλ“œ 등을 상속받아 μ‚¬μš©ν•˜λ©° μžμ‹ ν΄λž˜μŠ€μ—μ„œ μΆ”κ°€ 및 ν™•μž₯을 ν•  수 μžˆλŠ” 것을 λ§ν•©λ‹ˆλ‹€.
        • 이둜 인해 μž¬μ‚¬μš©μ„±, μ€‘λ³΅μ„±μ˜ μ΅œμ†Œν™”κ°€ μ΄λ£¨μ–΄μ§‘λ‹ˆλ‹€.
    • κ΅¬ν˜„(Implements)
      • λΆ€λͺ¨ μΈν„°νŽ˜μ΄μŠ€(Interface)λ₯Ό μžμ‹ ν΄λž˜μŠ€μ—μ„œ μž¬μ •μ˜ν•˜μ—¬ κ΅¬ν˜„ν•˜λŠ” 것을 λ§ν•©λ‹ˆλ‹€.
        • μƒμ†κ³ΌλŠ” 달리 λ°˜λ“œμ‹œ λΆ€λͺ¨ 클래슀의 λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•˜μ—¬ κ΅¬ν˜„ν•΄μ•Ό ν•©λ‹ˆλ‹€.
    • 상속과 κ΅¬ν˜„μ˜ 차이
      • 상속은 일반 클래슀, abstract 클래슀λ₯Ό 기반으둜 κ΅¬ν˜„ν•˜λ©°, κ΅¬ν˜„μ€ μΈν„°νŽ˜μ΄μŠ€λ₯Ό 기반으둜 κ΅¬ν˜„ν•©λ‹ˆλ‹€.