[java] 자바 프록시 패턴의 예제와 설명

프록시 패턴은 객체 지향 소프트웨어 디자인에서 사용되는 패턴 중 하나입니다. 이 패턴은 한 객체에 대한 접근을 제어하기 위해 다른 객체를 둬서, 접근을 제어하고 싶은 객체에 대한 간접적인 대리자(Proxy) 역할을 수행합니다. 자바에서는 프록시 패턴을 구현하는 여러 방법이 있지만, 가장 흔히 사용되는 방법은 동적 프록시 이며, 이를 위해 java.lang.reflect 패키지의 Proxy 클래스를 사용합니다.

프록시 패턴은 실제 객체와 클라이언트 사이에 중개자 역할을 하며, 실제 객체에 대한 접근을 제어하거나 보안 검사, 캐싱, 로깅과 같은 기능을 수행할 수 있습니다.

동적 프록시 패턴 사용 예제

다음은 동적 프록시 패턴을 사용한 간단한 예제입니다. 이 예제는 List 객체에 대한 접근을 제어하는 프록시 패턴을 구현한 것입니다.

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.ArrayList;

public class ListProxyExample {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        List<String> listProxy = (List<String>) Proxy.newProxyInstance(
                ListProxyExample.class.getClassLoader(),
                new Class[] { List.class },
                new ListProxyHandler(list)
        );
        
        listProxy.add("apple");
        listProxy.add("banana");
        System.out.println(listProxy);  // 출력: [apple, banana]
    }
}

class ListProxyHandler implements InvocationHandler {

    private List<String> list;

    public ListProxyHandler(List<String> list) {
        this.list = list;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("add")) {
            // 접근을 허용하지 않음
            throw new UnsupportedOperationException("접근이 허용되지 않습니다.");
        } else {
            return method.invoke(list, args);
        }
    }
}

이 예제에서 ListProxyHandler 클래스는 List 객체에 대한 접근을 제어하고 있습니다.

동적 프록시 패턴을 사용하면 접근 제어, 로깅, 성능 측정 등 다양한 기능을 추가로 구현할 수 있으며, 실제 객체의 변경 없이 클라이언트 요청을 제어할 수 있습니다.

프록시 패턴을 사용하면 객체 간의 결합도를 줄이고 유연한 구조를 유지할 수 있습니다.

결론

프록시 패턴은 중요한 객체에 대한 접근을 제어하여 유연한 소프트웨어 디자인을 가능케 합니다. 자바에서는 java.lang.reflect.Proxy를 사용하여 동적 프록시를 구현할 수 있으며, 이를 활용하여 다양한 기능을 유연하게 추가할 수 있습니다.

참고 자료: