본문 바로가기
까망 동네/디자인 패턴

[디자인 패턴] 프록시 패턴 (Proxy Pattern)

by 까망 하르방 2023. 11. 11.
반응형

🎈 프록시 패턴 (Proxy Pattern) 

• 대상 원본 객체를 대신 처리하여 로직 흐름을 제어하는 패턴

• 프록시(Proxy) 사전적인 의미는 '대리인'

 (= 누군가에게 어떤 일을 대신 시키는 것을 의미)

 활용방안: 보안, 캐싱, 데이터 유효성 검사, 지연 초기화, 로깅 등

• 디자인 패턴 중 구조 패턴에 해당된다.

 

💻 디자인 패턴(Design Pattern)이란?

👨‍💻 디자인 패턴(Design Pattern)이란? • SW 개발 방법 중에서도 구조적인 문제 해결에 목적을 둔다. • 알고리즘과 같이 특정 문제를 해결하는 Logic 형태보다는 특정 상황에 적용할 수 있는 방

zoosso.tistory.com

 

 

프록시 패턴 필요성

Q) 객체에 직접적으로 접근하면 되지 번거롭게 대리자를 통하는 이유는 무엇일까?

- 대상 클래스가 민감한 정보를 가지고 있는 경우

- 대상 객체가 무거운 경우

- 대상 객체에 기능 추가/변경이 쉽지 않은 경우

 

C++에서도 메모리 누수를 방지하고 자동으로 메모리를 해제하기 위해

스마트 포인터인 std::shared_ptr 또는 std::unique_ptr가 있는데

이는 대표적인 프록시 패턴 예시이다

 

 

[예제 코드]

 프록시 패턴 적용 X

#include <iostream>
#include <string>

class Image {
public:
    Image(const std::string& filename) : filename(filename) {
        LoadImage();
    }

    void Display() {
        std::cout << "[출력]: " << filename << std::endl;
    }

private:
    std::string filename;


    void LoadImage() {
        std::cout << "[로딩]: " << filename << std::endl;
    }
};

int main() {
    Image image("example.jpg");

    puts("---- ---- ----");
    image.Display();

    return 0;
}

 

프록시 패턴 예시

 

클라이언트(main)에서 image 객체를 생성하고 출력하고 있다.

Display() 메서드를 호출하기 전부터 이미지 생성/로딩을 하는데,

이는 리소스 낭비하고 있다고 볼 수 있다.


 

[예제 코드]

• 프록시 패턴 적용 O

#include <iostream>
#include <string>

class Image {
public:
    virtual void Display() = 0;
};

class RealImage : public Image {
public:
    RealImage(const std::string& filename) : filename(filename) {
        LoadImage();
    }

    void Display() override {
        std::cout << "[출력]: " << filename << std::endl;
    }

private:
    std::string filename;

    void LoadImage() {
        std::cout << "[로딩]: " << filename << std::endl;
    }
};

class ImageProxy : public Image {
public:
    ImageProxy(const std::string& filename) : filename(filename), realImage(nullptr) {}

    void Display() override {
        if (realImage == nullptr) {
            realImage = new RealImage(filename);
        }
        realImage->Display();
    }
private:
    std::string filename;
    RealImage* realImage;
};

int main() {
    Image* image = new ImageProxy("example.jpg");

    puts("---- ---- ----");

    image->Display();

    return 0;
}

 

프록시 패턴 예시

 

Display() 메서드 호출할 때, 이미지가 로딩된다.

실제 객체 생성하거나 초기화하지 않고

클라이언트 요청에 응답하여 리소스를 효율적으로 관리할 수 있다. (성능 향상)

 

이러한 방법을 "지연 초기화/로딩 (Lazy Initialization/Loading)"라고 하는데

데이터베이스 엔티티나 이미지 등에서 활용된다.


 

프록시 패턴 유의사항

• 복잡성 증가: 프록시 패턴 도입으로 추가적인 클래스와 인터페이스 필요

• 성능 저하: 중간에서 처리하기에 직접 접근하는 것보다 성능저하가 발생할 수 있다.

 

 

🎈 다른 디자인 패턴과 비교

• 어댑터 (Adapter)

두 개의 객체를 이어준다는 역할적인 측면에서 두 패턴은 서로 유사하다.

어댑터 패턴은 서로 다른 인터페이스를 호환해주는 것이 목적이고

프록시 패턴은 객체에 대한 직접 접근을 제어하고 추가 동작을 수행하는 것에서 차이가 있다.

 

[디자인패턴] 어댑터 패턴 (Adapter Pattern)

🎈 어댑터 패턴 (Adapter Pattern) • 호환되지 않는 인터페이스를 가진 두 개의 클래스를 함께 사용할 수 있게 한다. • 상속 보다는 위임하는 형태 권장 상속은 실수로라도 접근할 수 있기에 데이

zoosso.tistory.com

반응형

댓글