[Gof 디자인패턴] Proxy 패턴

600g (Kim Dong Geun)·2021년 6월 18일
0

프록시 패턴

  • 의도
    • 다른 객체에 대한 접근을 제어하기 위하 대리자 또는 자리채움자 역할을 하는 객체.
  • 프록시 종류
    1. 원격 프록시 : 서로 다른 주소 공간에 존재하는 객체를 가리키는 대표 객체로, 로컬환경에 위치
    2. 가상 프록시 : 요청이 있을때만 필요한 고비용 객체를 생성할때 사용
    3. 보호 프록시 : 원래 객체에 대한 실제 접근을 제어, 객체별로 접근 제어 권한이 다를때 유용하게 사용
    4. 스마트 포인터 : 실제 객체 접근이 일어날때 추가적인 행동을 담당하는 객체, 객체 에 대한 참조 조사, 객체에 대한 lock등
  • 구조

  • Proxy

    • 실제로 참조할 대상에 대한 참조자를 관리
      • RealSubject와 Subject 인터페이스가 동일하면 프록시는 Subject에 대한 참조자를 가짐.
    • Subject와 동일한 인터페이스를 제공하여 실제 대상을 대체할 수 있어야 함
    • 실제 대상에 대한 접근을 제어하고 실제 대상의 생성과 삭제를 책임짐
    • 프록시는 종류에 따라서 다음을 수행
    프록시 종류설명
    Remote Proxy요청 메시지와 인자를 인코딩하여 이를 다른 주소공간에 있는 실제 대상에게 전달
    장점 : 객체의 실제 호출 위치를 숨길 수 있음
    Virtual Proxy실제 대상에 대한 추가적 정보를 보유하여 실제 접근에 대한 지연
    장점 : 객체에 대한 생성시점을 관리할 수 있음
    Protection Proxy요청한 대상이 실제 요청할 수 있는 권한이 있는지 확인
    장점 : 객체에 대한 추가적인 관리를 수행할 수 있음
/**
 * @author Donggeun.kim
 */
public interface Content {

	/**
	 * 컨텐트 내용을 보여준다 객체.
	 */
	void showContent();
}

public class ContentLoaderProxy implements Content {

	private Optional<Content> maybeContent = Optional.empty();

	/**
	 * 비디오 객체 다운로드
	 */
	@Override
	public void showContent() {
		maybeContent.ifPresentOrElse(content -> {
			System.out.println("====로딩 완료====");
			content.showContent();
		}, () -> {
			long startTime = System.currentTimeMillis();
			try {
				System.out.println("로딩... 다운로드 중 : 10%");
				Thread.sleep(3000L);

				System.out.println("로딩... 다운로드 중 : 50%");
				Thread.sleep(3000L);

				System.out.println("로딩... 다운로드 중 : 95%");
				Thread.sleep(3000L);

				maybeContent = Optional.of(new VideoContent());
				maybeContent.get().showContent();

			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("다운로드 시간 : "+ (System.currentTimeMillis() - startTime)/1000 +" sec" );
		});
	}

}

public class Main {
	public static void main(String ...args){
		Content content = new ContentLoaderProxy();
		content.showContent();
	}
}

  • Protection 혹은 이외의 커스텀 프록시들
/**
 * @author Donggeun.kim
 */
public class ContentStatisticsProxy implements Content{

	private Content content;

	public ContentStatisticsProxy(Content content) {
		this.content = content;
	}

	@Override
	public void showContent() {
		System.out.println("로그 or 통계 or 뭐 스마트 포인터 일련의 작업들, 혹은 트랜잭션 시작");
		content.showContent();
		System.out.println("로그 마무리 통계 마무리 스마트포인터 마무리, 일련의 작업들, 트랜잭션 커밋 or 롤백 작업");
	}
}

public class Main {
	public static void main(String ...args){
		Content content = new ContentLoaderProxy();
		content.showContent();

		System.out.println();
		System.out.println();

		//어떻게 보면 책임연쇄 작업도 가능

		Content content2 = new ContentStatisticsProxy(content);
		content2.showContent();
	}
}

  • 다른 패턴들과의 차이
    • Adapter 패턴
      • 서로 맞지 않는 인터페이스의 동작을 동기화 하기 위해 사용
    • 데코레이터 패턴
      • 각 서비스를 추가 하는 거지만 Proxy는 횡단관심, 장식자는 핵심관심에 대한 거라 볼 수 있음.
  • 실제로 Proxy 패턴도 굉장히 매우 많이 사용되고 있고, 스프링의 Filter, AOP, DI, Transaction,Interceptor, Filter 안쓰이는 곳이 없을 정도로 많이 쓰이고 있음.
profile
수동적인 과신과 행운이 아닌, 능동적인 노력과 치열함

0개의 댓글