Java 디자인 패턴-05.Proxy
(Java 디자인 패턴 스터디 모집 중 : https://github.com/bluedskim/javaDesignPatterns)
패턴 다이어그램
“특정 클래스 대신 그 클래스와 동일한 인터페이스를 구현한 래퍼 wrapper 클래스 Proxy 를 이용한다” (출처:https://refactoring.guru/design-patterns/proxy)
해결하려는 문제
- 특정 객체에 대한 접근을 통제할 수 있는 일관된 방법이 필요할 때(보안, 권한 체크).
- 네트워크 접속, 메모리에 탑재된 대형 객체, 파일, 그 외 생성에 큰 비용이 발생하거나 복제가 불가능한 리소스들 등에 대한 캐시가 필요할 때.
특징/용도
- proxy클래스는 client의 요청을 subject에 단순히 전달하는 목적으로 사용하거나 subject의 메소드를 호출하기 이전, 이후에 특정 로직을 추가고자 할 때 사용한다.
- client입장에서는 proxy를 사용하든 subject를 사용하든 기능상 차이는 없다(black box).
- 지연된 초기화 Lazy initialization (virtual proxy) : 클래스 생성시 초기화 하는 것이 아니라 해당 객체의 메소드를 호출 할 때 초기화 하도록 함
고려사항
- 유사한 패턴과 비교
- 어댑터 패턴은 subject와는 다른 인터페이스를 제공하는 반면 프록시는 동일한 인터페이스을 제공한다. 데코레이터 패턴은 subject보다 향상된(기능 추가) 인터페이스를 제공한다.
- 파사드 패턴은 복잡한 엔티티들의 초기화에 대한 버퍼를 제공한다는 점에서 proxy패턴과 유사하다. 하지만 프록시는 동일한 인터페이스을 제공한다는 점에서 차이가 있다.
- 데코레이터 패턴과 프록시 패턴은 복합 composition 을 사용한다는 점에서는 동일하지만 프록시 패턴은 subject 에 대한 라이프 사이클을 proxy내부에서 관리하는 반면 데코레이터 패턴에서는 클라이언트가 대상의 라이프사이클을 관리한다는 차이가 있다.
- Proxy내에서 클라이언트 목록을 관리할 수도 있다. 사용하는 클라이언트가 없다면 리소스를 해제하는 등의 처리작업 수행하고자 할 때 유용하다.
클래스 다이어그램
소스
- Proxy : Subject를 대체하고자 하는 객체(Proxy.java)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
package net.dskim.desingpattern.proxy.solution;
import lombok.extern.slf4j.Slf4j;
import net.dskim.desingpattern.proxy.HeavyResource;
import net.dskim.desingpattern.proxy.Resource;
/**
* Proxy객체도 역시 Resource 인터페이스를 구현해야 한다.
*/
@Slf4j
public class Proxy implements Resource {
/**
* Proxy객체가 다루어야 할 Subject객체
*/
private HeavyResource heavyResource;
public Proxy() {
super();
log.info("Proxy 생성 완료");
}
/**
* 처리 메소드를 호출 시
* 지연된 초기화Lazy initialize 하도록 한다.
*/
@Override
public String process() {
// null check 하여 불필요한 초기화를 피한다.
if (heavyResource == null) {
this.heavyResource = new HeavyResource();
}
return heavyResource.process();
}
}
|
- Subject : 숨기고자 하는 객체(HeavyResource.java)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
package net.dskim.desingpattern.proxy;
import lombok.extern.slf4j.Slf4j;
/**
* Subject 객체
*
*/
@Slf4j
public class HeavyResource implements Resource {
/**
* 생성자 호출시 초기화에 많은 시간과 자원이 소모된다고 가정한다.
*/
public HeavyResource() {
super();
log.info("HeavyResource 초기화 중...");
log.info("HeavyResource 초기화 완료");
}
/**
* 실제 어떤 처리를 하는 메소드
*/
@Override
public String process() {
log.info("processing...");
return "processed";
}
}
|
- Resource : proxy와 subject가 구현해야 하는 인터페이스(Resource.java)
1
2
3
4
5
6
7
8
|
package net.dskim.desingpattern.proxy;
/**
* 모든 리소스가 구현해야 하는 인터페이스
*/
public interface Resource {
public String process();
}
|
참고