본문 바로가기
컴퓨터 과학/디자인패턴

[디자인패턴] 구조 패턴(3) : 프록시(Proxy)

by webcodur 2024. 3. 24.
728x90
반응형

목차

     

    프록시(Proxy)

    프록시(Proxy) 디자인 패턴은 구조적 디자인 패턴의 일종으로, 어떤 다른 객체에 대한 접근을 제어하기 위해 그 객체의 대리자 또는 자리표시자를 제공한다. 이 패턴의 목적은 접근 제어, 비용이 많이 드는 연산의 지연 실행, 네트워크 연결 등의 문제를 해결하는 것에 있다.

    패턴명의 어원

    "프록시"라는 용어는 대리인이나 대변인을 의미하는 'Proxy Agent'에서 유래했다. 즉, 어떤 객체 대신해서 일을 처리하는 객체를 말한다. 프록시 객체는 실제 객체와 같은 인터페이스를 구현함으로써, 클라이언트가 실제 객체를 직접 호출하는 것처럼 느끼게 하면서도 추가적인 기능(예: 접근 제어, 지연 로딩 등)을 제공한다.

    패턴 미적용 예시 코드

    먼저, 프록시 패턴을 적용하지 않은 간단한 예시를 살펴보자. 이 예에서는 이미지를 로드하는 간단한 기능을 가진 클래스가 있다고 가정한다.

    public interface IImage
    {
        void Display();
    }
    
    // 실제 이미지를 로드하고 표시하는 클래스
    public class RealImage : IImage
    {
        private string fileName;
    
        public RealImage(string fileName)
        {
            this.fileName = fileName;
            LoadFromDisk(fileName);
        }
    
        public void Display()
        {
            Console.WriteLine("Displaying " + fileName);
        }
    
        private void LoadFromDisk(string fileName)
        {
            Console.WriteLine("Loading " + fileName);
        }
    }
    
    // 클라이언트 코드
    public class Client
    {
        public static void Main(string[] args)
        {
            IImage image = new RealImage("test.jpg");
            image.Display(); // 이미지를 로드하고 표시
        }
    }

     

    위 코드에서 RealImage 클래스는 객체가 생성될 때 바로 파일로부터 이미지를 로딩한다. 이 경우, 클라이언트 코드에서 RealImage 객체를 생성하면 즉시 파일 로딩이 시작되므로, 아직 이미지를 실제로 표시할 필요가 없는 상황에서 로딩 비용이 발생 한다.

     

    패턴 적용 예시 코드

    프록시 패턴을 적용하면, 실제 이미지 로딩 작업을 프록시 객체가 대신 처리하게 만들 수 있다. 이렇게 하면 실제 이미지가 필요한 순간까지 로딩을 지연시킬 수 있다.

    // 이미지 인터페이스와 실제 이미지 클래스는 동일하게 유지
    
    // 프록시 클래스
    public class ProxyImage : IImage
    {
        private RealImage realImage;
        private string fileName;
    
        public ProxyImage(string fileName)
        {
            this.fileName = fileName;
        }
    
        public void Display()
        {
            if (realImage == null)
            {
                realImage = new RealImage(fileName);
            }
            realImage.Display();
        }
    }
    
    // 클라이언트 코드 변경
    public class Client
    {
        public static void Main(string[] args)
        {
            IImage image = new ProxyImage("test.jpg");
            image.Display(); // 실제로 표시할 때까지 이미지 로딩 지연
        }
    }

     

    프록시 패턴을 적용한 후, ProxyImage 클래스는 실제 RealImage 객체의 생성을 지연시킨다. 클라이언트는 ProxyImage를 통해 이미지에 접근하므로, Display 메소드가 호출될 때까지 이미지 로딩이 발생하지 않는다. 이로 인해 불필요한 리소스 사용을 줄이고, 애플리케이션의 성능을 향상할 수 있다.

     

    문제점 및 해결

    패턴 미적용 시 발생하는 문제점:

    • 비효율적 리소스 사용: 예제에서 보듯, RealImage 객체는 생성 시점에 바로 이미지를 로딩한다. 이는 이미지를 실제로 사용할 필요가 없는 경우에도 리소스를 낭비하게 만든다.
    • 접근 제어 부재: 클라이언트가 객체에 직접 접근할 때, 접근을 제어하거나 추가 로직을 적용하기 어렵다. 예를 들어, 특정 조건에서만 이미지를 로딩하도록 제한하거나, 로딩 전후에 추가 작업을 수행하기 어렵다.

    프록시 패턴 적용으로 얻는 이점:

    • 지연 로딩 (Lazy Loading): 프록시를 통해 실제 객체의 생성과 초기화를 필요한 순간까지 지연시킬 수 있다. 이는 애플리케이션의 시작 시간을 단축하고, 리소스 사용을 최적화하는 데 도움을 준다.
    • 접근 제어: 프록시를 통해 실제 객체에 대한 접근을 제어할 수 있다. 이를 통해 권한 검사, 요청의 필터링, 객체의 생명 주기 관리 등 추가적인 작업을 쉽게 적용할 수 있다.
    • 투명성: 클라이언트는 프록시 객체를 실제 객체와 동일한 방식으로 사용할 수 있다. 이는 디자인 패턴을 적용하면서도 클라이언트 코드의 변경을 최소화할 수 있음을 의미한다.

     

    프록시 패턴의 종류

    프록시 패턴은 사용 목적에 따라 여러 종류로 분류될 수 있다:

    • 가상 프록시 (Virtual Proxy): 객체의 생성을 지연시키는데 사용된다. 위의 예제는 가상 프록시의 예이다.
    • 보호 프록시 (Protection Proxy): 객체에 대한 접근을 제어한다. 예를 들어, 특정 사용자에게만 객체에 대한 접근 권한을 부여할 수 있다.
    • 원격 프록시 (Remote Proxy): 네트워크상의 다른 주소 공간에 존재하는 객체에 대한 로컬 표현을 제공한다. 이를 통해 원격 객체와의 통신을 간단하게 할 수 있다.
    • 스마트 참조 (Smart Reference): 객체가 참조될 때 추가적인 행동을 수행한다. 예를 들어, 객체에 대한 참조가 더 이상 없을 때 자동으로 리소스를 해제할 수 있다.

    프록시 패턴은 이러한 다양한 형태와 용도로 활용되며, 객체 지향 프로그래밍에서 중요한 디자인 패턴 중 하나로 꼽힌다. 이 패턴을 통해 애플리케이션의 유연성을 높이고, 코드의 재사용성을 개선할 수 있다.

    반응형