디자인패턴 - 구조패턴 - 프록시(Proxy)

waonderboy·2022년 3월 14일
1

디자인 패턴

목록 보기
3/3
post-thumbnail

프록시 패턴

프록시 패턴의 정의와 사용

📖 proxy[prɒk.si]
선거에서 다른 사람을 위해 투표하는 등 다른 사람을 위해 행동할 수 있는 권한 또는 이 권한이 부여된 사람
출처 - cambridge 사전


프록시는 사전적인 의미로 대리인을 의미한다. 사전적인 의미와 객체지향의 관점으로 바라보면 특정 객체에 직접 접근하지 않고 대리 객체를 통해 원하는 객체에 접근 할 것이라고 추론 할 수 있다. 프록시 패턴을 이용하면 클라이언트카 특정 객체의 오퍼레이션에 접근하기전에 프록시 객체를 지나 접근 하도록 하는 패턴이다. 프록시 패턴은 클라이언트로 부터 타겟 객체의 복잡성을 커버하기 위해 Wrapper를 생성해야 할 때 사용되며. 이를 이용한 예시로는 캐시와 로깅이 있고, 또한 프록시에 보안을 적용해 해당객체에 접근제어를 하도록 하거나 성능 측정을 하는 등의 방법이 있다.

만약 보안이나 성능측정과 같은 방식들을 접근 하고자 하는 객체의 메서드로 구현한다면 객체의 코드는 복잡해지고 다른 기능을 갖게되어 단일 책임 원칙(Single Responsibility Principle)을 위반하게 될 것이다. 때문에 프록시 패턴을 사용하면 이를 어기지 않고 사용할 수 있을 것이다.

프록시 패턴을 이용한 다른 예시로는 생성하는데 많은 리소스를 필요하는 인스턴스를 미리 생성하거나 Lazy initialization를 이용해 사용 시 구현 할 수 있다. 또한 프록시를 통해 로깅이나 캐싱과 같은 개념을 구현할 수 있다.

스프링의 AOP가 프록시패턴으로 구현되어있다.



프록시 패턴 구현

그림 1 - 프록시 패턴 클래스 다이어그램

위 클래스 다이어그램을 통해 구현해보자.

  1. Naive proxy pattern
    단지 프록시의 기능만 신경써서 만들어 보았다.
// proxy
public class GameServiceProxy extends GameService {
    @Override
    public void startGame() throws InterruptedException {
        long before = System.currentTimeMillis();
        super.startGame();
        System.out.println(System.currentTimeMillis() - before);
    }
}
.
.
// service
public class GameService {
    public void startGame() throws InterruptedException {
        System.out.println("Game Start!");
        Thread.sleep(1000L);
    }
}
.
.
// client
public class Client {
    public static void main(String args[]) throws InterruptedException {
        GameService gameService = new GameServiceProxy();
        gameService.startGame();
    }
}

위와 같은 코드는 더 이상의 service를 만들기 불편하기 때문에 interface를 이용해 클래스 다이어그램에 따라 만들어 보았다.

  1. Lazy initialization
// interface
public interface GameService {
    void startGame() throws InterruptedException;
}
.
.
// interface 구현체 - game service
public class DefaultGameService implements GameService{
    @Override
    public void startGame() throws InterruptedException {
        Thread.sleep(1000L);
        System.out.println("Game Start!");
    }
}
.
.
// interface 구현체 - proxy
public class GameServiceProxy implements GameService{

    private GameService gameService;

    @Override
    public void startGame() throws InterruptedException {
        long before = System.currentTimeMillis();
        if (this.gameService == null ) {
            this.gameService = new DefaultGameService();
        }
        gameService.startGame();
        System.out.println(System.currentTimeMillis() - before);
    }
}
.
.
// client
public class Client {
    public static void main(String args[]) throws InterruptedException {
        GameService gameService = new GameServiceProxy();
        gameService.startGame();
    }
}





접근 제한 프록시 구현

프록시 패턴을 이용하여 접근 제한 프록시를 구현해 볼 것이다.

// Proxy
public class ProxyInternet implements Internet{

    private Internet internet;
    private static List<String> bannedSite;

    static {
        bannedSite = new ArrayList<>();
        bannedSite.add("illegal.com");
        bannedSite.add("bat777.com");
    }

    public ProxyInternet(Internet internet) {
        this.internet = internet;
    }

    @Override
    public void connectTo(String serverHost) throws Exception {
        if (bannedSite.contains(serverHost.toLowerCase())) {
            throw new Exception("Access Denied");
        }
        internet.connectTo(serverHost);
    }
}
.
.
// Client
public class Client {
    public static void main(String args[]) throws Exception {
        Internet site = new ProxyInternet(new RealInternet());

        // connect
        site.connectTo("nabor.com");
        site.connectTo("bat777.com");
    }
}

Internet 인터페이스와 구현체는 생략하였다. 특정 사이트에 대해 접근 제한할때 다음과 같이 만들 수 있다.


프록시 패턴 정리

  • 프록시 패턴은 대리 객체를 통해 원하는 객체의 오퍼레이션을 이용하는 것이다
  • 프록시 패턴은 크게 3가지의 기능(가상, 원격, 보호)을 띄도록 만들 수 있는데 이 3가지 기능의 예시로 가상 - 캐싱, 원격 - Google docs, 보호 - 접근제어를 들 수 있다.
  • 타겟 객체에 접근에 대해 사전처리를 할 수 있다.
  • 객체를 생성할 때 추가적인 단계를 거치므로 빈번한 객체 생성이 필요한 경우 성능이 저하될 수 있다.
    - 이런 상황에서는 런타임 프록시를 만들어 사용할 수 있다. (추후에 정리)
  • 로직이 난해해져 가독성이 떨어질 수 있다.







Reference

profile
wander to wonder 2021.7 ~

0개의 댓글