CS/객체지향설계 & 패턴

[객체지향설계 & 패턴] 프록시 패턴

hyeon0117 2025. 5. 30. 15:46

프록시 패턴

 객체의 책임과 관련이 있는 프록시(Proxy) 패턴이다. 프록시 패턴의 핵심은 '객체가 필요해지면 만든다'인데, 대리자 Proxy가 객체를 생성하는 것이다. 프록시 패턴의 기본적인 구조는 다음과 같다. 

 UML 그리는 툴이 익숙하지 않아 Subject 인터페이스에 request1, 2, 3 메소드들이 추가되지 않았는데 원래  Subjec에 request1, 2, 3 메소드가 존재한다. 

 Subject는 Proxy와 RealSubject를 동일시하기 위한 API를 정의하고, Proxy는 클라이언트의 요청을 최대한 처리하는 역할을 맡는다. 클라이언트의 요청을 Proxy 혼자서 처리할 수 없다면 RealSubject에 처리를 맡겨야 하는데, 여기서 Proxy 패턴의 핵심이 등장한다. RealSubject 인스턴스를 미리 만들어 놓는 것이 아닌 RealSubject 인스턴스가 필요할 때 생성해 클라이언트의 요청을 수행한다. 앞에서 언급한 '객체가 필요해지면 만든다'는 것은 이것이다. 

예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Subject 인터페이스
public interface Image {
    void display();
}
 
// RealSubject 클래스
public class RealImage implements Image {
    private String filename;
 
    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk(); // 실제 리소스 로딩
    }
 
    private void loadFromDisk() {
        System.out.println("Loading " + filename);
    }
 
    @Override
    public void display() {
        System.out.println("Displaying " + filename);
    }
}
 
// Proxy 클래스
public class ProxyImage implements Image {
    private RealImage realImage;
    private String filename;
 
    public ProxyImage(String filename) {
        this.filename = filename;
    }
 
    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename); // 실제 이미지가 필요할 때 로딩
        }
        realImage.display();
    }
}


cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Main {
    public static void main(String[] args) {
        Image image = new ProxyImage("test_image.jpg");
 
        System.out.println("이미지 객체 생성 완료. 아직 로딩 안됨.");
        System.out.println();
 
        // 실제 이미지가 필요할 때 로딩됨
        image.display();
 
        System.out.println();
 
        // 이미 로딩되었으므로 다시 로딩하지 않음
        image.display();
    }
}
cs

 

 위 예시 코드를 통해 프록시 패턴을 더 뜯어보자. Image 클래스는 Subject, RealImage는 RealSubject에 해당하며 Proxy의 역할은 ProxyImage 클래스가 맡았다.

 Main 클래스의 Iamge image = new ProxyImage("test_image.jpg") 코드가 실행되면 어떻게 될까? image의 realImage 필드는 null이고 fileName만 test_image.jpg로 생성자 코드가 실행된다. 이후, image.display() 코드가 실행되면, realImage가 null이므로 이때 realImage에 RealImage 객체가 배정된다. 따라서 RealImage 클래스의 loadFromDisk 메소드가 실행되어 Loading + filename가 출력되고, 이후 Displaying + filename도 출력될 것이다.
 그리고 마지막으로 다시 이미지를 display하는데, 이때는 RealImage 객체가 이미 생성되었으므로 Loading 문장이 출력되지 않고 바로 DisPlaying 문장이 결과로 출력될 것이다. 

확장

 프록시 패턴에는 가상 / 원격 / 보호 프록시 종류가 있다. 먼저 가상 프록시는 위에서 설명한 프록시 패턴으로, 실제 인스턴스가 필요한 시점에 생성 / 초기화를 수행한다.

 원격 프록시는 투과적으로 RealSubject의 메소드를 이용할 수 있는 프록시 패턴이며, 보호 프록시는 RealSubject 역의 기능에 대해 접근 제한을 설정하는 패턴이다. 보호 프록시 패턴에서는 지정된 사용자라면 메소드 호출을 허가하지만, 나머지는 오류를 발생하도록 하는 프록시이다.