반응형

프록시 패턴(Proxy Pattern)

  - Proxy는 대리자, 대변인 이라는 뜻이다. 

  - 프록시 패턴은 구조패턴(Structural Pattern) 중 하나이다.
  - 구조 패턴은 작은 클래스들을 상속과 합성을 이용하여 더 큰 클래스를 생성하는 방법을 제공하는 패턴이다.

  - 인터페이스나 구현을 복합하는 것이 아니라 객체를 합성하는 방법을 제공한다.

    이는 컴파일 단계에서가 아닌 런타임 단계에서 복합 방법이나 대상을 변경할 수 있다는 점에서 유연성을 갖는다.

 

프록시의 주요 기능

프록시를 통해서 할 수 있는 일은 크게 2가지로 나뉜다.

1. 접근 제어 (권한에 따른 접근 차단, 캐싱 등)

2. 부가 기능 추가 (다른 로직을 추가하는 등의 부가 기능을 수행, 예) 실행 시간을 측정해서 로그를 남긴다.)

 

* GOF 디자인 패턴에서는 의도에 따라서 프록시 패턴과, 데코레이터 패턴으로 구분한다.

  - 프록시 패턴 : 접근 제어가 목적

  - 데코레이터 패턴 : 새로운 기능 추가가 목적

 

프록시 패턴의 장점

  - 제어의 흐름을 변경하거나 다른 로직을 수행하기 위해 사용한다.

  - 객체에 대하여 접근할 때에 Wrapper Class를 두어 접근에 대한 통제를 위해 사용된다.

 

코드

  * 더하기 빼기 계산기 로직을 구현 예제 (프록시 패턴을 이용해서 계산 시간을 출력)

 

  - 계산기 interface

 

public interface Calculator {

    public int plus(int left, int right);
    public int subtract(int left, int right);

}

 

  - 계산기 interface 구현 service

 

public class CalculatorService implements Calculator{

    private int result;

    @Override
    public int plus(int left, int right) {
        result = left + right;
        return result;
    }

    @Override
    public int subtract(int left, int right) {
        result = left - right;
        return result;
    }
}

 

  - 프록시 패턴을 사용하지 않은 테스트

 

@SpringBootTest
class CalculatorServiceTest {

    @Test
    void calculatorService() {

        Calculator calculatorService = new CalculatorService();

        int left = 10000;
        int right = 5000;

        int plusResult = calculatorService.plus(left, right);
        int subtractResult = calculatorService.subtract(left, right);

        assertEquals(plusResult, left+right);
        assertEquals(subtractResult, left-right);

    }

}

 

  - 프록시 패턴 클래스

 

public class CalculatorServiceProxy implements Calculator{

    private int result;

    @Override
    public int plus(int left, int right) {
        long beforeTime = System.currentTimeMillis();

        result = left + right;
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long afterTime = System.currentTimeMillis();
        long secDiffTime = (afterTime - beforeTime)/1000;
        System.out.println(" plus 계산 시간(m) : "+secDiffTime);

        return result;
    }

    @Override
    public int subtract(int left, int right) {
        long beforeTime = System.currentTimeMillis();

        result = left - right;
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        long afterTime = System.currentTimeMillis();
        long secDiffTime = (afterTime - beforeTime)/1000;
        System.out.println("subtract 계산 시간(m) : "+secDiffTime);

        return result;
    }
}

 

- 프록시 패턴을 사용한 테스트

 

@SpringBootTest
class CalculatorServiceTest {

    @Test
    void calculatorServiceProxy() {

        Calculator calculatorServiceProxy = new CalculatorServiceProxy();

        int left = 10000;
        int right = 5000;

        int plusResult = calculatorServiceProxy.plus(left, right);
        int subtractResult = calculatorServiceProxy.subtract(left, right);

        assertEquals(plusResult, left+right);
        assertEquals(subtractResult, left-right);

    }


}

 

결과 : plus 계산 시간(m) : 1
        subtract 계산 시간(m) : 2

 

 

정리

 - 프록시 패턴의 의도 : 다른 객체에 접근을 제어하기 위해 대리자를 제공

 - 테스트 코드를 보면 생성 객체만 바꿈으로서 Calculator interface는 영향을 받지 않게 Proxy 클래스를 통해서 원하는 목적에 맞게 흐름을 조정할 수 있었다. 해당 패턴은 Spring 프레임워크에 AOP 동작원리에 사용되어지고 있다.

 * 중요한 점은 흐름제어만 할 뿐 결과값을 조작하거나 변경시키면 안된다.

 

참조 

 - https://readystory.tistory.com/132?category=822867

728x90
반응형

+ Recent posts