Design Pattern, Proxy

2022. 1. 12. 15:45ETC/Design Patterns

Structural Object Pattern

Proxy Pattern

 

-----------------    INDEX     -----------------

 

Proxy Pattern ?

Structure

Sample Code: Java

Applicability

  원격 프록시 Remote Proxy

  가상 프록시 Virtual Proxy

  보호 프록시 Protection Proxy

  스마트 참조자 프록시 Smart Reference Proxy

관련 패턴

 

----------------------------------------------

 

Provide a surrogate or placeholder for another object to control access to it.

- GoF Design Patterns

 

프록시 패턴은 실제 객체에 직접 접근하지 않고 접근을 제어하는 대리자surrogate or placeholder를 제공하는 패턴입니다.

 

 

프록시proxy대리인을 의미하며,

실제 객체에 직접 접근하지 않고 똑같이 동작하는 대리자surrogate를 생성하여 동작시킵니다.

 

무거운 동작들은 실제 객체에서 처리하되, 가볍고 부수적인 일들은 직접 처리하지 않고 대리자를 내세워 처리합니다.

 

Proxy는 마치 회사 대표의 비서와 같은 역할을 한다고 할 수 있습니다.

예를 들어, 한 회사의 대표와 미팅을 한다고 해볼게요.

 

대표와 일정을 맞추고 미팅 장소를 직접 정하지 않습니다. 비서를 통해 일정과 장소를 정합니다.

그리고 무게가 있는 핵심적인 일이나 권한이 필요한 일은 대표와 직접 만나 수행할 수 있습니다.

Proxy 패턴에서의 Proxy가 바로 이 비서의 역할을 하며, 실제 객체가 대표라고 이해하시면 됩니다.

 

주로 객체를 정교하게 제어해야 하거나 객체 참조가 필요한 경우 프록시 패턴을 사용합니다.

 

 

More Details

 

[GoF Design Patterns] - Proxy Communication Diagram

 

 

다이어그램을 통해 이해를 더해보겠습니다.

 

먼저, aClient에서 subject를 호출하게 되면 어떤 일이 벌어질지 예상해보세요.

Subject를 호출하면 실제 객체인 aRealSubject가 불러와져야겠지만, aProxy가 중간 단계 대리자로 먼저 불러와집니다.

그리곤, aProxy가 속성으로 가지고 있던(실제 객체의 위임) aRealSubject를 호출하여 실제 작업을 처리하게 됩니다.

 

 

이제 감이 조금 오시나요? 구조를 확인하며 개념을 선명하게 만들어볼게요!

 

 

 

Structure

 

[GoF Design Patterns] - Proxy Class Diagram

 

Subject

RealSubject와 Proxy의 공통 인터페이스를 정의합니다.

 

프록시는 실제 객체의 역할을 대신 수행합니다.

실제 객체와 프록시는 동일한 객체처럼 보이며 그렇게 동작합니다.

그래서 Proxy는 원본 객체와 동일한 인터페이스를 적용해 투명성을 갖도록 설계됩니다.

 

 

Proxy

RealSubject에 대한 액세스를 제어하며, 생성하고 삭제하는 역할을 합니다.

프록시가 실제 객체에 접근할 수 있도록 RealSubject의 참조를 갖습니다.

 

이때, 프록시가 RealSubject을 대체할 수 있도록 RealSubject와 동일한 인터페이스Subject를 가집니다.

 

 

RealSubject

프록시가 나타내는 실제 객체를 정의합니다.

 

 

Sample Code: Java

아주 거대한 문서를 불러온다고 가정해봅시다.

문서 안에는 텍스트 문자와 그림 등이 포함되어 있습니다.

문서를 처음 열었을 때, 모든 텍스트 데이터와 이미지들을 한꺼번에 불러오려면 시간이 꽤나 많이 필요할거에요.

그림들의 크기가 아주 크다면 더 많은 비용이 들겠죠?

 

Proxy 패턴을 사용한 "Lazy Initialization"을 사용하면 문서 불러오기의 최적화를 할 수 있어요.

문서를 불러올 때 모든 그림들을 불러오는 것이 아니고, 필요할 때 필요한 객체만 생성하는 거에요.

 

[GoF Design Patterns]

 

이미지 처리를 위해 Graphic Interface를 정의하고,

이를 구현한 Image와 대리자 역할을 해줄 ImageProxy에서 구현했습니다.

이 때 짚고 갈 점은 프록시가 대리 역할을 수행해야하므로 동일한 인터페이스를 사용했다는 점입니다. 

 

DocumentEditor에서 이미지를 불러올 때, 모두 불러오는 게 아니라

필요한 이미지만 불러오려고 한다면 어떻게 구현해야할까요?

 

ImageProxy를 생성할 때 속성으로 갖고 있는 Image객체를 생성하지 않습니다.

생성자에서 image 속성을 따로 설정하지 않습니다

Draw() 메서드를 확인해보면, image의 유무를 판별하여 필요할 때만 생성이 되게끔 만듭니다.

이렇게 필요할 때만 생성해서 실제 객체의 동작을 불러옵니다.

 

이제 코드로 확인해볼게요.

 

 

Graphic

public interface Graphic {
    void showImage();
}

 

ImageProxy

public class ImageProxy implements Graphic {
    private Image image;
    private String fileName;

    public ImageProxy(String fileName) {
        this.fileName = fileName;
    }

    public Image getImage() {
        if(this.image == null){
            this.image = new Image(this.fileName);
        }
        return image;
    }

    @Override
    public void showImage() {
        if(this.image == null) {
            this.image = getImage();
        }
        getImage().showImage();
    }
}

 

Image

public class Image implements Graphic {
    private String fileName;

    public Image(String strFileName){
        this.fileName = strFileName;
    }

    @Override
    public void showImage() {
        System.out.println("Show Image : " +fileName);
    }
}

 

Client

public class Client {
    public static void main(String[] args) {
        final Graphic img1 = new ImageProxy("Image***1");
        final Graphic img2 = new ImageProxy("Image***2");

        img1.showImage();
        img2.showImage();
    }
}

 

 

Applicability

Remote Proxy

원격 프록시Remote Proxy는 프록시 패턴을 가장 많이 응용하는 적용 사례이며, 주로 데이터 전달을 목적으로 사용합니다.

객체에 대한 요청과 그 요청에 대한 인수arguments를 처리encoding한 후 실제 객체에 보내는 역할을 합니다.

프록시 패턴은 객체를 분리하는 역할을 하고, 원격 프록시는 분리된 객체에 투과적 특성을 결합해 객체의 연결을 제어합니다.

 

Virtual Proxy

가상 프록시Virtual Proxy온디맨드(요청·요구에만 요청에 대한 결과값을 줌) 형식으로 객체를 생성합니다.

무거운 실제 객체의 부담을 덜기위함입니다.

위에서 본 ImageProxy가 바로 가상 프록시의 예시입니다.

 

📌 Cache

캐시는 데이터나 값을 미리 복사해 놓는 임시 장소나 동작을 의미입니다.

하나의 예시로, 웹 HTTP에서 프록시라는 단어를 많이 사용하는데요.

프록시는 HTTP에서 웹페이지를 캐시 처리함으로써 속도를 개선하고 우회 접속을 시도합니다.

 

Virtual Proxy는 실제 객체에 대한 추가 정보를 캐시하여 액세스를 프록시 객체로 미룰 수 있습니다. 

 

 

Protection Proxy

보호 프록시는 실제 개체에 대한 액세스를 제어합니다.

프록시에서 권한을 먼저 확인하고 실제 객체를 생성(접근)할지를 판단합니다. 

보호 프록시는 개체의 액세스 권한이 서로 달라야 할 때 유용합니다. 

 

아주 간단한 Github Code 를 확인해보시면 이해해 도움이 될 듯 합니다.

 

 

Smart Reference

스마트 참조는 객체에 액세스할 때 추가 작업을 수행하는 원시 포인터를 대체합니다.

어떻게 활용할까요? 바로 아래와 같은 역할들을 수행할 수 있습니다.

 

✔️ 스마트 포인터 : 실제 객체에 대한 참조 수를 계산하여, 참조가 사라지면 자동으로 해제될 수 있게끔 만들수 있습니다.
✔️ 영구 객체persistent object를 처음 메모리에 로드할 때 참조할 수 있습니다.
✔️ 액세스하기 전에 실제 객체가 잠겨 있는지 확인하여 다른 객체가 변경할 수 없도록 제한 할 수 있습니다.

 

 

---

 

프록시 패턴은 구현되는 정도에 따라 다양합니다.

 

Protection Proxy는 데코레이터와 완전히 똑같이 구현될 수 있습니다.

Remote Proxy는 실제 제목에 대한 직접적인 참조는 포함하지 않고 host ID호스트의 로컬 주소와 같이 간접 참조만 포함합니다.

Virtual Proxy는 파일 이름과 같은 간접 참조로 시작하지만 결국 직접 참조를 가져와 사용합니다.

 

이처럼 Proxy 패턴은 다양한 용도로 사용할 수 있고, 실제로 사용되고 있습니다.

 

 

 

관련 패턴

C- Creational Patterns  |  S - Structural Patterns  |  B - Behavioral Patterns

 

 

S: Adapter

어댑터 패턴은 서로 다른 인터페이스를 맞춰주는 역할을 하는 반면, 프록시 패턴은 동일한 인터페이스로 제공(투과적 특성)합니다.

다만, Protection Proxy는 권한을 확인하고 실제 객체가 실행을 거부할 수 있기 때문에 실제 객체의 부분집합으로 볼수도 있습니다.

 

 

 

S: Decorator

Protection Proxy와 장식자 패턴은 객체를 동적으로 확장하여 실행할 수 있다는 점에서 비슷합니다.

하지만, 둘은 다른 목적을 지닙니다.

장식자 패턴의 목적이 새로운 기능을 추가하는 것이라면, 보호용 프록시는 접근을 제어하기 위해 코드를 추가합니다.

 

 

 

 

 

 

 

그럼 지금까지 Proxy Pattern에 대해 알아보았습니다.

오타나 잘못된 내용이 있다면 댓글로 남겨주세요!

감사합니다 ☺️ 

 

 

 

모든 Design Patterns 모아보기

 

Design Patterns

안녕하세요. GoF 디자인 패턴을 정리하고자 합니다. 디자인 패턴은 일주일 전부터 공부를 시작했는데, 스스로 설명하듯 적는게 익히는데 도움이 클 것같아 정말 오랜만에 시리즈로 포스팅하려

gngsn.tistory.com

 

'ETC > Design Patterns' 카테고리의 다른 글

Design Pattern, Adapter  (0) 2022.01.23
Design Pattern, Observer  (0) 2022.01.21
Design Pattern, Abstract Factory  (0) 2022.01.05
Design Pattern, Factory Method  (0) 2022.01.03
Design Pattern, Template Method  (0) 2022.01.01