예시 코드

class Subject {
    private val observers = mutableListOf<Observer>()

    fun registerObserver(observer: Observer) {
        observers.add(observer)
    }

    fun unregisterObserver(observer: Observer) {
        observers.remove(observer)
    }

    fun notifyObservers() {
        for (observer in observers) {
            observer.notifyObserver()
        }
    }
}
interface Observer {
    fun notifyObserver()
}

class ConcreteObserverA : Observer {
    override fun notifyObserver() {
        // Do something
    }
}

class ConcreteObserverB : Observer {
    override fun notifyObserver() {
        // Do something
    }
}

개념

Observer Pattern은 한 객체의 상태변화를 다른 객체 그룹에 알려야 할 때 사용되는 디자인 패턴이다. 상태변화를 알려야하는 객체 그룹을 미리 알 수 없거나, 그룹요소들이 동적으로 변경되는 경우 사용할 수 있다.

비유

  • 단체 채팅방

    상황

    • 기능 → 단체 채팅방
    • 행동 → 한 명이 채팅을 보내면 채팅방의 구성원들이 알람 수신

    적용

    interface EventListener {
        fun update(msg: String)
    }
    
    class ChattingMessageListener(val name: String) : EventListener {
        override fun update(msg: String) {
            createPushNotification(msg)
        }
    }
    class ChattingRoom {
        private val members = mutableListOf<ChattingMessageListener>()
    
        fun addMember(member: ChattingMessageListener) {
            members.add(member)
        }
    
        fun removeMember(with = member: ChattingMessageListener) {
            members.remove(member)
        }
    
        fun sendMessageToAllMembers(msg: String, author: String) {
            for (member in members) {
                member.update(msg, author)
            }
        }
    }
    
    fun main() {
        val chattingRoom = ChattingRoom()
        
        val members = arrayOf<ChattingMessageListener>(
            ChattingMessageListener("John"),
            ChattingMessageListener("Choi"),
            ChattingMessageListener("Yoon")
        )
        
        members.forEach { member -> chattingRoom.addMember(with = member) }
    
        chattingRoom.sendMessage("Hello", members[1].name)
    }
  • 주식 알림

    상황

    • 기능 → 주식 가격 알림
    • 행동 → 종목 가격이 변경되면 투자자들에게 알림을 보내줌

    적용

    abstract class Stock(val symbol: String, private val price: Double) {
    	private val investors = mutableListOf<IInvestor>()
    
    	fun attach(investor: IInvestor) {
    		investors.add(investor)
    	}
    
    	fun detach(investor: IInvestor) {
    		investors.remove(investor)
    	}
    
    	fun notify() {
    		for (investor in inverstors) {
    			investor.update(this)
    		}
    	}
    
    	fun setPrice(price: Double) {
    		this.price = price
    		notify()
    	}
    }
    class Apple(symbol: String, price: Double) : Stock(symbol, price)
    interface IInvestor {
    	fun update(stock: Stock)
    }
    class Investor(val name: String) : IInvestor {
    	override fun update(stock: Stock) {
    		println("$name is notified that ${stock.symbol}'s price change to ${stock.price}")
    	}
    }

장단점

장점

  • OCP (개방-폐쇄 원칙)
    • 확장에는 열려있고, 수정에는 닫혀 있어야 한다.

단점

  • 레이스 컨디션
    • 알림을 보내는 중에 옵저버가 등록됐을 때
    • 알림을 보내는 중에 옵저버가 등록해제됐을 때
  • 순환 실행
    • 이벤트 X가 발생했을 때, 옵저버 A가 옵저버 B를 갱신하고, 옵저버 B가 옵저버 A를 갱신한다면 순환 실행이 일어난다.


출처

https://refactoring.guru/ko/design-patterns/observer

https://ko.wikipedia.org/wiki/옵서버_패턴


Uploaded by N2T

+ Recent posts