Kotlin 객체지향 디자인 패턴
Java 객체지향 디자인 패턴 책을 보고 Kotlin으로 변환하면서 공부한 내용입니다
9장. 옵저버 패턴
-
옵저버 패턴이란?
- 데이터의 변경이 발생했을 경우 상대 클래스나 객체에 의존하지 않으면서 데이터 변경을 통보하고자 할 때 유용하다
- 통보 대상 객체의 관리를 Subject 클래스와 Observer 인터페이스로 일반화한다
- 데이터 변경을 통보하는 클래스는 통보 대상 클래스나 객체에 대한 의존성을 없앨 수 있다
- 결과적으로 옵저버 패턴은 통보 대상 클래스나 대상 객체의 변경에도 ConcreteSubject 클래스를 수정 없이 그대로 사용할 수 있도록 한다

-
성적 출력 예시
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import java.lang.Integer.min
class ScoreRecord {
private val scores: MutableList<Int> = mutableListOf()
private lateinit var dataSheetView: DataSheetView
fun setDataSheetView(dataSheetView: DataSheetView) {
this.dataSheetView = dataSheetView
}
fun addScore(score: Int) {
scores.add(score)
dataSheetView.update()
}
fun getScoreRecord() : MutableList<Int> = scores
}
class DataSheetView(private val scoreRecord: ScoreRecord, private val viewCount: Int) {
fun update() {
val record = scoreRecord.getScoreRecord()
displayScores(record, viewCount)
}
fun displayScores(record: MutableList<Int>, viewCount: Int) {
println("list of $viewCount entries: ")
for(i in 0 until min(record.size, viewCount)) {
println(record[i])
}
println()
}
}
fun client() {
val scoreRecord = ScoreRecord()
val dataSheetView = DataSheetView(scoreRecord, 3)
scoreRecord.setDataSheetView(dataSheetView)
for(i in 0 until 6) {
val score = i * 10
println("adding $score")
scoreRecord.addScore(score)
}
}
-
문제점
- 성적을 다른 형태로 출력하고 싶다면?
- 여러 가지 형태의 성적을 동시 혹은 순차적으로 출력하려면?
-
해결책
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import java.lang.Integer.min
import java.util.*
interface Observer {
abstract fun update()
}
abstract class Subject {
private val observers: MutableList<Observer> = mutableListOf()
fun attach(observer: Observer){
observers.add(observer)
}
fun detach(observer: Observer) {
observers.remove(observer)
}
// 통보 대상 목록, 즉 각 옵저버에게 변경을 통보
fun notifyObserver() {
observers.forEach {o ->
o.update()
}
}
}
class ScoreRecord : Subject() {
private val scores: MutableList<Int> = mutableListOf()
fun addScore(score: Int) {
scores.add(score)
notifyObserver()
}
fun getScoreRecord() : MutableList<Int> = scores
}
class DataSheetView(private val scoreRecord: ScoreRecord, private val viewCount: Int) : Observer {
// 통보 받음
override fun update() {
val record = scoreRecord.getScoreRecord()
displayScores(record, viewCount)
}
// 변경 통보 시 리스트 목록 출력
fun displayScores(record: MutableList<Int>, viewCount: Int) {
println("list of $viewCount entries: ")
for(i in 0 until min(record.size, viewCount)) {
println(record[i])
}
println()
}
}
class MinMaxView(private val scoreRecord: ScoreRecord) : Observer {
// 통보 받음
override fun update() {
val record = scoreRecord.getScoreRecord()
displayMinMax(record)
}
// 변경 통보 시 최소값, 최대값 출력
fun displayMinMax(record: MutableList<Int>) {
val minValue = Collections.min(record, null)
val maxValue = Collections.max(record, null)
println("Min: $minValue , Max : $maxValue")
}
}
// StatisticsView는 Observer를 구현함으로써 통보 대상이 됨
class StatisticsView(private val scoreRecord: ScoreRecord) : Observer {
// 통보 받음
override fun update() {
val record = scoreRecord.getScoreRecord()
displayStatistics(record)
}
// 변경 통보 시 조회된 점수의 합과 평균을 출력함
fun displayStatistics(record: MutableList<Int>) {
var sum = 0
record.forEach { score ->
sum += score
val average: Float = (sum / record.size).toFloat()
println("Sum: $sum, Average: $average")
}
}
}
fun client() {
val scoreRecord = ScoreRecord()
val dataSheetView = DataSheetView(scoreRecord, 3)
scoreRecord.attach(dataSheetView)
val minMaxView = MinMaxView(scoreRecord)
scoreRecord.attach(minMaxView)
for(i in 1 until 6) {
val score = i * 10
println("adding $score")
scoreRecord.addScore(score)
}
scoreRecord.detach(dataSheetView)
val statisticsView = StatisticsView(scoreRecord)
scoreRecord.attach(statisticsView)
for(i in 1 until 6) {
val score = i * 10
println("adding $score")
scoreRecord.addScore(score)
}
}
client()