엔지니어 규의 IT 프로그래밍 다이어리

[Kotlin] 16. 익명객체와 옵저버 패턴 (난이도 : ★★★★★) 본문

프로그래밍 언어/코틀린

[Kotlin] 16. 익명객체와 옵저버 패턴 (난이도 : ★★★★★)

엔지니어 규 2022. 5. 19. 23:08
728x90

옵저버

 

'옵저버' 란 '이벤트가 일어나는 것을 감시' 하는 감시자의 역할을 만든다고 하여 Observer 라고 부른다.

 

안드로이드를 예로 들자면 '키의 입력', '터치의 발생', '데이터의 수신' 등 함수로 직접 요청은 안했어도 시스템 또는 루틴에의 해 발생하는

 

동작들을 '이벤트' 라고 부르며 이 이벤트가 발생할때마다 즉각 처리하도록 만드는 패턴을 '옵저버 패턴'이라고 한다. 

 

옵저버 패턴을 구현할 때는 두개의 클래스가 필요하다.

위 그림처럼  class A는 이벤트를 수신하고 class B는 이벤트의 발생 및 전달을 처리한다고 할때, 이와 같은 방법에는 문제가 있다.

 

일반적으로 이벤트를 수신하는 class A 의 필요에 따라 이벤트를 발생시키는 클래스의 인스턴스를 생성하여 사용하기 때문에,

 

A 는 B를 직접 참조 할 수 있지만, B는 A 를 참조할 방법이 없다.

 

그래서 이사이에 '인터페이스'를 끼워 넣는다.

 

B에서는 자신의 이벤트를 받아줄 수 있는 인터페이스를 만들어 공개하고, A는 이를 구현하여 B에 넘겨주면 

 

인터페이스만 알아도 event를 넘겨줄 수 있다. 이때 이 인터페이스를 'observer' 또는 'listener' 라고 부르며

 

이렇게 이벤트를 넘겨주는 행위를 'call back' 이라고 한다.

 

 

이해를 돕기위해 코드를 통해서 더 자세히 알아보도록 하자

 

우리가 구현할 코드는 

이벤트를 수신해서 출력하는 EventPrinter,

숫자를 카운트하며 5의 배수마다 이벤트를 발생시킬 Counter,

이 두개를 연결시킬 인터페이스인 EventListener 로 이루어져 있다.

 

 

아래 코드를 확인해 보자.

fun main(){

    EventPrinter().start()

}

interface EventListener{
    fun onEvent(count: Int)
}

class Counter(var listener: EventListener){

    fun count(){
        for (i in 1..100){
            if(i % 5==0) listener.onEvent(i)
        }
    }
}

class EventPrinter : EventListener {
    override fun onEvent(Count :Int){
        print("${Count}-")
    }
    fun start(){
        val counter = Counter(this)
        counter.count()
    }
}

5-10-15-20-25-30-35-40-45-50-55-60-65-70-75-80-85-90-95-100-

 

여기서 Counter의 인스턴스를 만들되, this 라는 키워드로 EventListener의 구현부를 넘겨준다.

 

그리고 counter.count() 구문을 적어줌으로써 count를 시작한다.  

fun start(){
    val counter = Counter(this)
    counter.count()
}

 

여기서 this 는 EventPrinter 객체 자신을 나타내지만 받는쪽에서 'EventListener'만 요구했기떄문에,

EventListener 구현부만 넘겨주게 된다.

 

 

이를 객체지향의 다형성이라고 한다.

 

상속받아 만들어진 class 는 super class의 기능을 포함하여 제작되었으므로, super class 에서 정의한 부분만 따로 넘겨줄 수 있다.

 

EventPrinter.start() 를 main 함수에서 실행해보면 Counter 가 5의 배수마다 이벤트를 발생시킨것을,

EventPrinter 내에서 구현된 EventListener에서 출력하고 있음을 알 수 있다.

 

 

 

익명 객체 (Anonymous Object)

 

그런데 EventPrinter가 EventListener를 상속받아 구현하지 않고, 임시로 만든 EventListener 객체를 대신 넘겨줄 수 도 있다.

 

이것을 이름이 없는 객체라고 하여 익명객체(Anonymous Object)라고 부른다.

 

fun main(){

    EventPrinter().start()

}

interface EventListener{
    fun onEvent(count: Int)
}

class Counter(var listener: EventListener){

    fun count(){
        for (i in 1..100){
            if(i % 5==0) listener.onEvent(i)
        }
    }
}

class EventPrinter {
    fun start(){
        val counter = Counter(object: EventListener{
            override fun onEvent(count: Int){
                print("${count}-")
            }
        })
        counter.count()
    }
}

위의 코드를 실행해보면 같은결과가 나오는것을 알 수 있다.

 

observer 패턴은 이벤트를 기반으로 동작하는 모든 코드에서 광범위하게 쓰이는 방식이므로 그 구조를 이해하는것이 중요하다.

 

 

 

 

---------------------------------------------------------------------------------------------

번외 +

 

개인적으로 디자인 패턴은 코딩을 하면서 굉장히 중요한것으로 보이며, 또한 어려운 개념이기도 하다.

 

위의 개념은 차근차근 오랜시간동안 보며 이해를 해야 할 것 같다.

 

728x90
Comments