프록시 패턴이란?
실제 기능을 수행하는 객체 대신 가상의 객체를 사용해 로직의 흐름을 제어하는 디자인 패턴
프록시 패턴의 특징
- 원래 하려던 기능을 수행하며 그외의 부가적인 작업(로깅, 인증, 네트워크 통신 등)을 수행하기에 좋음
- 비용이 많이 드는 연산(DB 쿼리, 대용량 텍스트 파일 등)을 실제로 필요한 시점에 수행 가능
- 프록시 객체와 실제 객체의 사용법이 유사하므로 사용성이 좋음
1) 가상 프록시
가상 프록시는 실제 객체의 사용 시점을 제어할 수 있습니다.
ex> 문서를 디코딩하는 프로그램
//인터페이스
interface TextFile {
String fetch();
}
//구현체
class SecretTextFile implements TextFile {
private String plainText;
public SecretTextFile(String fileName) {
this.plainText = SecretFileHolder.decodeByFileName(fileName);
}
@Override
public String fetch() {
return plainText;
}
}
20개의 파일을 디코딩 해야 하는 프로그램이 있다고 가정하겠습니다. SecretTextFile
메서드는 암호화 된 파일을 디코딩하는 기능입니다.SecretTextFile
클래스에서 사용중인 SecretFileHolder.decodeByFileName()
메서드의 수행속도는 0.3초라고 가정합니다.
목록에 20개의 파일 내용을 노출해야 하는 상태였기 때문에 수행속도가 느리게 되는 문제점이 발생합니다.
화면을 구성할 때 이 SecretTextFile
들을 전부 객체로 만들다 보니 6초 정도의 로딩 시간을 갖게 된 것입니다.
//프록시 패턴
class ProxyTextFile implements TextFile {
private String fileName;
private TextFile textFile;
public ProxyTextFile(String fileName) {
this.fileName = fileName;
}
@Override
public String fetch() {
if (textFile == null) {
textFile = new SecretTextFile(fileName);
}
return "[proxy] " + textFile.fetch();
}
}
ProxyTextFile
같은 프록시 클래스를 만들고 기존SecretTextFile
클래스 대신 사용한것만으로도 초기 객체 생성 시간을 감소시킬 수 있습니다. 이렇게 초기 비용이 많이 드는 연산이 포함된 객체의 경우 가상 프록시를 사용했을 때 효과를 볼 수 있습니다.
2) 보호 프록시
보호 프록시는 프록시 객체가 사용자의 실제 객체에 대한 접근을 제어합니다.
ex> 사원정보 조회 프로그램
// 직책 등급(차례대로 직원, 매니저, 사장)
enum GRADE {
Staff, Manager, President
}
// 구성원
interface Employee {
String getName(); // 이름 조회
GRADE getGrade(); // 직책 조회
String getInformation(Employee viewer); // 사원정보 조회
}
// 일반 구성원
class NormalEmployee implements Employee {
private String name;
private GRADE grade;
public NormalEmployee(String name, GRADE grade) {
this.name = name;
this.grade = grade;
}
@Override
public String getName() {
return name;
}
@Override
public GRADE getGrade() {
return grade;
}
@Override
public String getInformation(Employee viewer) {
return "Display " + getGrade().name() + " '" + getName() + "' personnel information.";
}
}
해당 사원정보 프로그램에서 정보 접근 권한을 제한하려고 합니다.
현재 상태에서는 모든 사람이 타인의 정보를 조회할 수 있습니다. 상위 직책이거나 본인만 사원정보를 조회할 수 있도록 하는 기능을 추가합니다.
만약 해당 코드를 본인이 수정할 수 있다면 기능을 추가하는 일은 쉽지만, 라이브러리와 같이 내부 코드를 수정할 수 없을 경우에 프록시 패턴을 사용한다면 유용합니다.
//보호 프록시 패턴 적용
class ProtectedEmployee implements Employee {
private Employee employee;
public ProtectedEmployee(Employee employee) {
this.employee = employee;
}
@Override
public String getInformation(Employee viewer) {
// 본인 인사정보 조회
if (this.employee.getGrade() == viewer.getGrade()
&& this.employee.getName().equals(viewer.getName())) {
return this.employee.getInformation(viewer);
}
switch (viewer.getGrade()) {
case President:
// 사장은 매니저, 스탭들을 볼 수 있다.
if (this.employee.getGrade() == GRADE.Manager || this.employee.getGrade() == GRADE.Staff) {
return this.employee.getInformation(viewer);
}
case Manager:
if (this.employee.getGrade() == GRADE.Staff) { // 매니저는 스탭들을 볼 수 있다.
return this.employee.getInformation(viewer);
}
case Staff:
default:
throw new RuntimeException(); // 스탭들은 다른 사람의 인사정보를 볼 수 없다.
}
}
@Override
public String getName() {
return employee.getName();
}
@Override
public GRADE getGrade() {
return employee.getGrade();
}
}
ProtectedEmployee 같은 프록시 클래스를 만들고 기존 NormarEmployee 클래스 대신 사용함으로써 기존 코드의 수정 없이 객체에 대한 접근을 제어하는 기능을 추가할 수 있습니다.
그 외 패턴
- 원격 프록시 : 원격 객체에 대한 접근 제어가 가능합니다.
- 방화벽 프록시 : 일련의 네트워크 자원에 대한 접근을 제어함으로써 주 객체를 '나쁜' 클라이언트들로부터 보호하는 역할을 합니다.
- 스마트 레퍼런스 프록시 (Smart Reference Proxy) : 주 객체가 참조될 때마다 추가 행동을 제공합니다. ex) 객체 참조에 대한 선 작업, 후 작업 등
- 캐싱 프록시 (Caching Proxy) : 비용이 많이 드는 작업의 결과를 임시로 저장 하고, 추후 여러 클라이언트에 저장된 결과를 실제 작업처리 대신 보여주고 자원을 절약하는 역할을 합니다.
- 동기화 프록시 (Synchronization Proxy) : 여러 스레드에서 주 객체에 접근하는 경우에 안전하게 작업을 처리할 수 있게 해줍니다. 주로 분산 환경에서 일련의 객체에 대한 동기화 된 접근을 제어해주는 자바 스페이스에서 쓰입니다.
- 복잡도 숨김 프록시 (Complexity Hiding Proxy) : 복잡한 클래스들의 집합에 대한 접근을 제어하고, 복잡도를 숨깁니다.
- 지연 복사 프록시 (Copy-On-Write Proxy) : 클라이언트에서 필요로 할 때까지 객체가 복사되는 것을 지연시킴으로써 객체의 복사를 제어합니다. '변형된 가상 프록시'라고 할 수 있으며,
Java 5 의 CopyOnWriteArrayList 에서 쓰입니다.
Reference
'JAVA' 카테고리의 다른 글
DAO와 repository의 차이 (0) | 2021.09.14 |
---|---|
Proxy 객체 (0) | 2021.09.07 |
디자인 패턴 (0) | 2021.08.06 |
Object 클래스 - 메서드 (0) | 2021.08.05 |
Constant Pool (0) | 2021.08.05 |