ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Design Pattern] 프록시 패턴 (Proxy Pattern)
    공부/디자인 패턴 2021. 5. 9. 20:13

    프록시 패턴이란 프록시 의미 그대로 실제 기능을 수행하는 주체(RealSubject)를 바로 호출하는 대신 대리자(Proxy)를 거쳐서 호출하는 것입니다. 즉, 클라이언트 → 실제 기능을 담당하는 객체 가 아닌, 클라이언트 → 프록시 객체 → 실제 기능을 담당하는 객체의 흐름으로 진행됩니다.

    클래스 다이어그램

    장점

    실제 기능을 담당하는 객체의 리소스가 무거운 경우, 프록시 객체에서 간단한 처리를 하거나(클라이언트의 요청에 대한 유효성 검사를 통해 유효한 경우만 메인 객체 호출) 캐싱 처리를 통해 부하를 줄일 수 있습니다. 앞에서 설명한 간단한 처리를 통해 보안의 역할을 가질 수 있습니다.

    단점

    아무래도 클라이언트 - 메인 객체 사이에 프록시 객체가 끼어있는 상황이기에 응답이 느리거나 에러를 발생할 수도 있습니다.

    프록시 종류

    Virtual Proxy

    실제 기능을 담당하는 주체 클래스에 리소스가 집약적인 경우에 가상 프록시 패턴을 사용합니다. 예를 들어, 주체 클래스의 생성자에 시간이 오래 걸리는 작업이 있는데 동시에 많은 인스턴스화가 발생한다면 응답이 매우 느려집니다. 인스턴스화 이후 해당 바로 작업을 사용한다면 그나마 핑계가 되지만 사용하지 않는데도 작업이 실행된다면 문제가 됩니다. 이러한 문제를 주체 클래스의 수정이 아닌, 프록시 클래스를 생성해 실제로 사용할 때만 주체 클래스를 사용하도록 구현해 해결할 수 있습니다.

    public interface Control {
        String something();
    }
    public class Video implements Control {
        private String name;
        public Video(String name) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.name = name;
        }
        @Override
        public String something() {
            return name;
        }
    }
    
    public class ProxyVideo implements Control {
        private String name;
        private Control control;
    
        public ProxyVideo(String name) {
            this.name = name;
        }
    
        @Override
        public String something() {
            if (control == null) {
                this.control = new Video(name);
            }
    
            return this.control.something();
        }
    }
    

    주체 클래스인 Video를 생성하면 1초씩 대기를 한다고 가정했을 때, ProxyVideo 클래스를 통해 실제로 필요할 때만, 해당 객체를 생성해 사용할 수 있습니다.

    Protection Proxy

    주체 클래스에 대한 접근을 제어할 때 보호 프록시 패턴을 사용합니다. 클라이언트가 주체 클래스를 호출하려 할 때, 그 사이에서 허용할지 말지를 결정 할 수 있습니다. 또한 클라이언트의 권한에 따라 주체 클래스의 메소드를 호출하도록 구현할 수도 있습니다.

    public interface Control {
        Object something(Object video);
    }
    public class Video implements Control{
        private String name;
    
        @Override
        public Object something(Object video) {
    //        내부 로직 ~~~~
            return name;
        }
    
        public boolean hasVideo(Object video) {
            return video != null;
        }
    }
    public class ProxyVideo implements Control {
        private String name;
        private Video video;
    
        @Override
        public Object something(Object video) {
            if (this.video.hasVideo(video)) {
                return this.video.something(video);
            }
            return null;
        }
    }

    ProxyVideo 클래스에서 주체 클래스를 호출하기 전 클라이언트로부터 요청 받은 객체의 존재유무를 검사하고 유효할 때만 호출하는 예시입니다.

    Remote Proxy

    프록시 클래스는 로컬에 두고 주체 클래스는 원격에 둘 때, 리모트 프록시를 사용합니다. Google Docs 같은 것이 대표적인 예시입니다.

    파이썬

    파이썬에는 자바처럼 interface가 존재하지 않습니다. ABCMeta 모듈을 활용해 자바의 interface 기능을 유사하게 만들어 프록시 패턴을 구현할 수 있습니다.

    from abc import ABCMeta, abstractmethod
    
    class SubjectInterface(metaclass=ABCMeta):
        @abstractmethod
        def request(self, url):
            pass
    
    class RealSubject(SubjectInterface):
        def request(self, url):
            # 내부 구현
            return url.upper()
    
        @staticmethod
        def has_url(url):
            return url == ''
    
    class ProxyClass(SubjectInterface):
        def request(self, url):
            if RealSubject.has_url(url):
                return RealSubject().request(url)

    댓글