티스토리 뷰
목적
특정 인스턴스의 상태를 관찰(observe)하고 있는 구독자에게 변화를 발행(publish)한다.
방법
- 상태 변화를 발행할 수 있는 Publisher 인터페이스를 만든다. (GoF 옵저버 패턴에서는 Subject)
- subscribe : Observer를 추가한다.
- unsubscribe : Observer를 제거한다.
- publish : Observer에 변화된 상태를 발행한다.
- Publisher를 관측할 수 있는 Observer 인터페이스를 만든다. 구현에 따라 두가지 방법이 있다.
- Publisher로부터 변화된 상태를 갱신받는다(push). 정해진 정보만 갱신 받을 수 있다는 단점이 있다.
- update()에 publisher를 자신을 전달해서 필요한 데이터를 얻을 수 있도록 한다(pull). 원하는 정보를 받을 수 있지만 subject의 getter를 호출하기 때문에 관측하고 갱신한다는 패턴 목적에 조금 어긋난다.
예제
String value를 구독하고 발행할 수 있도록 push 방식의 옵저버 패턴을 구현해보자. 먼저 Publisher(Subject), Observer 인터페이스를 구현한다.
protocol StringPublisher {
var observers: [StringObserver] { get }
var value: String { get }
func subscribe(_ observer: StringObserver)
func publish()
}
protocol StringObserver: class {
func update(_ item: String)
}
StringPublisher를 채택하여 이름 클래스를 만들어보자.
// 1
class PersonName: StringPublisher {
var observers: [StringObserver] = []
var value: String
// 2
var name: String {
get {
return self.value
}
set {
self.value = newValue
publish()
}
}
init(_ initialValue: String) {
self.value = initialValue
}
func subscribe(_ observer: StringObserver) {
observers.append(observer)
}
func unsubscribe(_ observer: StringObserver) {
observers.removeAll { $0 === observer }
}
// 3
func publish() {
for observer in observers {
observer.update(value)
}
}
}
- StringPublisher protocol을 채택한다.
- value에 대한 getter, setter 역할을 한다. 새로운 값으로 set 되었을 때 publish()를 호출하여 변경사항을 발행한다.
- 자기 자신을 구독하고 있는 observer들의 update()를 호출하여 값을 발행한다.
사람의 이름은 학교에서도 사용하고, 회사에서도 사용할 수 있다. 학교와 회사는 이름을 관찰하고 있다가 이름이 바뀌면 적절히 업데이트 할 수 있어야 한다.
class School: StringObserver {
func update(_ item: String) {
print("school updated \(item)")
}
}
class Company: StringObserver {
func update(_ item: String) {
print("company updated \(item)")
}
}
이렇게 만든 publisher와 observer를 사용하면서 옵저버 패턴이 어떻게 사용되는지 알아보자.
let kim = PersonName("KIM")
let school = School()
let company = Company()
// 1
kim.subscribe(school)
kim.subscribe(company)
// 2
kim.name = "PARK"
// school updated PARK
// company updated PARK
// 3
kim.unsubscribe(school)
// 4
kim.name = "CHOI"
// company updated CHOI
- 김씨는 학교와 회사에 소속되어 있다.
- 어느날 김씨는 자신의 이름을 PARK으로 개명했다. 개명된 이름을 김씨가 소속되어 있던 학교와 회사 모두 개명된 이름을 전달 받았다.
- 김씨가 학교를 졸업하여 더이상 학교 소속이 아니게 되었다.
- 김씨가 자신의 이름을 CHOI로 개명하자 이번에는 회사만 전달 받았다.
push 방식으로 구현한 위 예제의 경우 이름을 표현하는 한 변수에 대한 구독을 하고 있지만, PersonName에 다른 값을 구독하고 싶다면 pull 방식을 사용할 수 있다. 구현에 따라 달라질 수 있지만 update()에 publisher 자기 자신을 전달하여 observer가 직접 원하는 값을 얻어가도록 구현할 수 있다.
'Programming > Design' 카테고리의 다른 글
책임연쇄패턴 : Chain of Responsibility (0) | 2017.01.08 |
---|
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- SwiftUI
- scala
- mongoDB
- 드라마
- C++
- swift
- SOCKET
- C
- ios
- game
- Cocos2d-x
- OS
- Java
- C/C++
- DesignPattern
- 데이터베이스
- winsock
- SHADER
- Spring
- 운영체제
- 국내여행
- 수학
- Git
- rxswift
- 자료구조
- ue4
- machine learing
- database
- 알고리즘
- JSP
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함