기타/자바 디자인패턴

[자바 디자인패턴] 5. Dynamic Proxy 패턴

창이2 2023. 3. 1. 13:29

안녕하십니까아.

이번 포스팅은 Dynamic Proxy 패턴에 대해서 써보려고 합니다.

Dynamic Proxy는 Proxy를 동적으로 생성하여 사용하는 패턴입니다.

Dynamic Proxy를 사용하는 경우는 대게 제네릭한 행동을 할때 사용됩니다.

 

가령 안드로이드 경우 Retrofit에서 이 방법을 사용하여 api호출을 하고있습니다.

 

이 패턴에서 알아야할 것은 InvocationHandler라는 것이 있습니다.

이 핸들러는 어떤 함수를 호출시 해당 호출에 대한 트리거 함수를 작성할 수 있습니다.

만약 Http의 Get 메소드를 호출하면 해당 메소드에 로그를 찍거나 하는 등의 기능을 할 수 있습니다.

 

일단 코드를 보면 HttpMethodInterface가 있고 이를 구현한 Impl클래스가 있습니다.

 

Proxy.newProxyInstance

 

를 이용하여 프록시 객체를 만듭니다. 프록시 객체는 클래스로더, 인터페이스, InvocationHandler를 받고 있습니다.

Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)

 

 

그리고 아래 해당 프록시가 함수를 호출할때 HttpProxyHandler의 invoke를 먼저 호출하는 것을 볼 수 있습니다.

target 은 인터페이스를 구체화한 클래스를, args 는 해당 메소드 호출시 들어있는 매개변수를 의미합니다. 

아래는 위 설명에 대한 예제코드입니다.

fun main() {
    val httpMethodProxy: HttpMethodInterface = Proxy.newProxyInstance(
        HttpMethodInterface::class.java.classLoader,
        arrayOf<Class<*>>(HttpMethodInterface::class.java),
        HttpProxyHandler(target = HttpMethodImpl()) // method 발생시 이벤트를 처리할 핸들러
    ) as HttpMethodInterface

    httpMethodProxy.get("GET arg")
    httpMethodProxy.post()
    httpMethodProxy.put()
    httpMethodProxy.delete()
}

class HttpProxyHandler(
    private val target: Any? // 특정 구체화된 클래스
) : InvocationHandler {

    // Method 발생시 트리거 되는 함수
    override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {
        println("-----------------------------------")
        HttpMethodInterface::class.members.forEach {
            if (method?.name?.contains(it.name) == true) {
                println("${it.name.uppercase(Locale.getDefault())} Method Called")
            }
        }
        println("Argument ${args?.get(0).toString()}")
        return method?.invoke(target, *args.orEmpty())
    }
}

class HttpMethodImpl: HttpMethodInterface {
    override fun get(string: String){
        println("GET")
    }
    override fun post(){
        println("POST")
    }
    override fun put(){
        println("PUT")
    }
    override fun delete(){
        println("DELETE")
    }
}

interface HttpMethodInterface {
    fun get(string: String){}
    fun post(){}
    fun put(){}
    fun delete(){}
}

 

결과화면

https://github.com/ckdrb7017/gof-design-pattern

 

GitHub - ckdrb7017/gof-design-pattern

Contribute to ckdrb7017/gof-design-pattern development by creating an account on GitHub.

github.com