루비로 작성된 옵서버
옵서버 패턴은 일부 객체들이 다른 객체들에 자신의 상태 변경에 대해 알릴 수 있는 행동 디자인 패턴입니다.
옵서버 패턴은 구독자 인터페이스를 구현하는 모든 객체에 대한 이러한 이벤트들을 구독 및 구독 취소하는 방법을 제공합니다.
복잡도:
인기도:
사용 사례들: 옵서버 패턴은 루비 코드, 특히 그래픽 사용자 인터페이스 컴포넌트들에서 매우 일반적입니다. 다른 객체들과의 클래스들과 결합하지 않고 해당 객체들에서 발생하는 이벤트들에 반응하는 방법을 제공합니다.
식별: 옵서버 패턴은 들어오는 메서드들을 목록에 저장하는 구독 메서드로 초기 식별할 수 있으며, 만약 위 구독 메서드가 목록의 객체들을 순회하고 그들의 '업데이트' 메서드를 호출하면 해당 패턴은 옵서버 패턴으로 확정지을 수 있습니다.
개념적인 예시
이 예시는 옵서버 패턴의 구조를 보여주고 다음 질문에 중점을 둡니다:
- 패턴은 어떤 클래스들로 구성되어 있나요?
- 이 클래스들은 어떤 역할을 하나요?
- 패턴의 요소들은 어떻게 서로 연관되어 있나요?
main.rb: 개념적인 예시
# The Subject interface declares a set of methods for managing subscribers. class Subject # Attach an observer to the subject. def attach(observer) raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end # Detach an observer from the subject. def detach(observer) raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end # Notify all observers about an event. def notify raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end end # The Subject owns some important state and notifies observers when the state # changes. class ConcreteSubject < Subject # For the sake of simplicity, the Subject's state, essential to all # subscribers, is stored in this variable. attr_accessor :state # @!attribute observers # @return [Array<Observer>] attr_accessor :observers private :observers def initialize @observers = [] end # List of subscribers. In real life, the list of subscribers can be stored # more comprehensively (categorized by event type, etc.). # @param [Observer] observer def attach(observer) puts 'Subject: Attached an observer.' @observers << observer end # @param [Observer] observer def detach(observer) @observers.delete(observer) end # The subscription management methods. # Trigger an update in each subscriber. def notify puts 'Subject: Notifying observers...' @observers.each { |observer| observer.update(self) } end # Usually, the subscription logic is only a fraction of what a Subject can # really do. Subjects commonly hold some important business logic, that # triggers a notification method whenever something important is about to # happen (or after it). def some_business_logic puts "\nSubject: I'm doing something important." @state = rand(0..10) puts "Subject: My state has just changed to: #{@state}" notify end end # The Observer interface declares the update method, used by subjects. class Observer # Receive update from subject. def update(_subject) raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end end # Concrete Observers react to the updates issued by the Subject they had been # attached to. class ConcreteObserverA < Observer # @param [Subject] subject def update(subject) puts 'ConcreteObserverA: Reacted to the event' if subject.state < 3 end end class ConcreteObserverB < Observer # @param [Subject] subject def update(subject) return unless subject.state.zero? || subject.state >= 2 puts 'ConcreteObserverB: Reacted to the event' end end # The client code. subject = ConcreteSubject.new observer_a = ConcreteObserverA.new subject.attach(observer_a) observer_b = ConcreteObserverB.new subject.attach(observer_b) subject.some_business_logic subject.some_business_logic subject.detach(observer_a) subject.some_business_logic output.txt: 실행 결과
Subject: Attached an observer. Subject: Attached an observer. Subject: I'm doing something important. Subject: My state has just changed to: 1 Subject: Notifying observers... ConcreteObserverA: Reacted to the event Subject: I'm doing something important. Subject: My state has just changed to: 10 Subject: Notifying observers... ConcreteObserverB: Reacted to the event Subject: I'm doing something important. Subject: My state has just changed to: 2 Subject: Notifying observers... ConcreteObserverB: Reacted to the event