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

Damsul·2023년 1월 11일
0

디자인패턴

목록 보기
4/15
post-thumbnail

실제 기능을 수행하는 객체 대신 가상의 객체를 사용해 로직의 흐름을 제어하는 구조 패턴

  1. 객체를 실제 사용하기 전까지 초기화를 미루고 싶을때 (Lazy init)
  2. 접근 권한 체크할 때
    사용한다.

출처 : 위키디피아

  • Subject : RealSubject와 Proxy를 위한 공통 인터페이스
  • RealSubject : 실제 기능을 제공하는 클래스
  • Proxy : RealSubject에 대한 접근을 제어하고, 객체의 생성과 삭제를 책임지는 클래스

예제

영화를 상영한다고 가정해 보자. 상영하고자 하는 영화를 정할 때마다 다운로드를 하면 자원 낭비가 심할 것이다. 이때 프록시 패턴을 이용하면 영화가 상영 시작하려는 시점에 다운로드를 해서 자원낭비 없이 볼 수 있다.

  • Subject

[Movie.java]

public interface Movie {
    void setMovieName(String name);
    String getMovieName();
    void start();
}
  • RealSubject

[Real_Movie.java]

public class Real_Movie implements Movie {
    private String name;

    public Real_Movie(String name) {
        this.name = name;
        download(this.name);
    }

    @Override
    public void setMovieName(String name) {
        this.name = name;
    }

    @Override
    public String getMovieName() {
        return this.name;
    }

    @Override
    public void start() {

        System.out.println(name + " | 상영 시작하겠습니다.");
    }

    private void download(String name) {
        System.out.println("상연 전 영화 (" + name + ") 다운로드 하겠습니다.");
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            System.out.println(".");
        }
        System.out.println("다운로드 완료.");

    }
}
  • Proxy

[Proxy_Movie.java]

public class Proxy_Movie implements Movie{
    private String name;
    private Real_Movie realMovie;

    public Proxy_Movie(String name) {
        this.name = name;
    }

    @Override
    public void setMovieName(String name) {
        this.name = name;
    }

    @Override
    public String getMovieName() {
        return this.name;
    }

    @Override
    public void start() {
        // 실제 영화 객체의 이름과 프록시 영화의 이름이 다른 경우
        // 다시 다운로드 받게 한다.
        realize();
        realMovie.start();
    }

    private synchronized void realize() {
        if (realMovie == null || !realMovie.getMovieName().equals(name)) {
            realMovie = new Real_Movie(this.name);
        }
    }
}
  • Client
public class Client {

    public static void main(String[] args) {
        Movie movie = new Proxy_Movie("공조");
        System.out.println("영화 제목 : " + movie.getMovieName());
        movie.setMovieName("신과 함께");
        System.out.println("영화 제목 : " + movie.getMovieName());
        movie.start(); // 객체 생성하고 다운로드 진행
        movie.start(); // 이미 객체가 생성되 있어 다시 다운로드를 받지 않아됨

        movie.setMovieName("범죄도시");
        System.out.println("영화 제목 : " + movie.getMovieName());
        movie.start(); // 영화가 바뀌었으므로 다시 객체를 생성해서 다운로드를 받아야 함
    }
}
  • 실행 결과

장단점

  • 장점

    • 기존 객체 수정없이 프록시 패턴을 통해 추가할 수 있다.
    • 사이즈가 큰 객체(이미지, 동영상)가 로딩되기 전에도 프록시를 통해 참조를 할 수 있다.
    • 실제 객체의 메소드를 숨기고 인터페이스를 통해 노출시킬 수 있다.(캡슐화)
    • 실제 객체 접근에 대해 사전처리를 할 수 있다.
    • 로컬에 있지 않고 떨어져있는 객체를 사용할 수 있다.
  • 단점

    • 성능이 저하될 수 있다.
      • 객체를 생성할 때 한 단계를 거치게 되므로, 빈번한 객체 생성이 필요한 경우
      • 프록시 내부에서 객체 생성을 위해 스레드가 생성, 동기화가 구현되어야 하는 경우
    • 코드가 복잡해질 수 있다.
      • 프록시 패턴이 추가될 때 로직이 복잡해져 가독성이 떨어질 수 있다.

종류

  • 가상 프록시 - 필요 시점까지 객체 생성 연기하지만 참조를 통해 객체를 이용할 수 있는 패턴
  • 원격 프록시 - 클라우드 환경의 Google Docs의 동작 원리처럼, 다른 주소 공간에 있는 객체를 프록시가 참조하도록 해 마치 같은 공간에 있는 것처럼 동작하게 하는 패턴
  • 보호 프록시 - 실제 객체에 대한 접근 제어를 위해 사용하는 패턴

Composite vs Decorator vs Proxy

  • Composite Pattern

    • 관련된 객체들을 하나의 인터페이스로 관리
  • Decorator Pattern

    • 상속 없이 동적으로 새로운 기능 추가
  • Proxy Pattern

    • 기능을 제공하는 대상에 대한 참조를 직접 관리하지 않음
profile
내 맘대로 작성하는 개발일지/ 작고 소중한 개발창고

0개의 댓글