다른 객체를 감싸서 접근을 제어할 때 사용
1. 의도
•
GoF
◦
다른 객체에 대한 접근을 제어하기 위한 대리자 또는 자리채움자 역할을 하는 객체를 둡니다.
•
Head First
◦
특정 객체로의 접근을 제어하는 대리인(특정 객체를 대변하는 객체)를 제공
2. 활용성
단순한 포인터보다는 조금 더 다방면에 활용할 수 있거나 정교한 객체 참조자가 필요할 때 적용할 수 있습니다.
2.1. 종류
•
Remote Proxy (원격 프록시)
◦
서로 다른 주소 공간에 존재하는 객체를 가리키는 대표 객체로, 로컬 환경에 위치
◦
원격 객체의 로컬 대변자 역할
◦
원격 객체로의 접근 제어
•
Virtual Proxy (가상 프록시)
◦
요청이 있을 때만 고비용 객체를 생성
◦
생성하기 힘든 자원으로의 접근 제어
•
Protection Proxy (보호 프록시)
◦
원래 객체에 대한 실제 접근을 제어함. 객체별로 접근 제어 권한이 다를때 유용하게 사용 가능
◦
접근 권한이 필요한 자원으로의 접근 제어
•
Smart Reference
◦
원시 포인터의 대체용 객체로, 실제 객체에 접근이 일어날때 추가적인 행동을 수행함
▪
Smart Pointer
•
실제 객체에 대한 참조 횟수를 저장하다가 더는 참조가 없을 때 자동으로 객체 제거
▪
맨 처음 참조되는 시점에 영속적 저장소의 객체를 메모리로 옮김
▪
실제 객체에 접근하기 전에, 다른 객체가 그것을 변경하지 못하도록 실제 객체에 대한 잠금(lock)을 검
3. 구조
•
UML Class Diagram
4. 참여자
•
Proxy는 종류에 따라 다음을 수행
◦
Remote Proxy
▪
요청 메세지와 인자를 인코딩하여 이를 다른 주소 공간에 있는 실제 대상에게 전달
◦
Virtual Proxy
▪
실제 대상에 대한 추가적 정보를 보유하여 실제접근을 지연할 수 있도록 해야 함
◦
Protection Proxy
▪
요청한 대상이 실제 요청할 수 있는 권한이 있는지 확인
참여자 | 역할 | 예시 |
Proxy | 1. 실제 참조할 대상에 대한 레퍼런스 관리
- RealSubject와 Subject 인터페이스가 동일시, 프록시는 Subject에 대한 레퍼런스를 가짐
2. Subject와 동일한 인터페이스를 제공하여 실제 대상을 대체할 수 있어야함
3. 실제 대상에 대한 접근을 제어하고 실제 대상의 생성과 삭제를 책임
RealSubject로의 접근을 제어하는 객체.
RealSubject 객체로의 접근 제어 | |
Subject | - RealSubject와 Proxy에 공통적인 인터페이스 정의
- RealSubject가 요청되는 곳에 Proxy를 사용할 수 있게 함 | |
RealSubject | 프록시가 대표하는 실제 객체
- 실제 작업을 대부분 처리하는 객체 |
5. 협력 방법
•
프록시 클래스는 자신이 받은 요청을 RealSubject 객체에 전달합니다.
6. 결과
•
간접화 통로
◦
프록시 패턴은 어떤 객체에 접근할 때 추가적인 간접화 통로를 제공합니다.
◦
간접화 통로의 용도
▪
Remote Proxy
•
객체가 다른 주소 공간에 존재한다는 사실 은닉 가능
▪
Virtual Proxy
•
요구에 따라 객체를 생성하는 등 처리 최적화 가능
▪
Protection Proxy & Smart Reference
•
객체가 접근할 때마다 추가 관리를 책임짐
•
객체를 생성할 건지 삭제할 건지 관리
•
기록 시점 복사 (copy-on-write)
◦
프록시 패턴이 사용자에게 숨길 수 있는 또다른 최적화
▪
중량급 객체에 대한 복사 비용 현격하게 줄어줌
◦
덩치가 크고 복잡한 객체를 복사할때 비용이 많이 듬. 사본이 변경되지 않고 원본이 똑같다면 비용이 발생 X
◦
프록시를 활용해서 복사 절차를 미룸 → 사본이 수정될 때만 실제 복사 비용을 물게 만듬
◦
원본의 참조 카운트 관리
▪
복사 기능 가능하기 위한 선행 작업
▪
프록시를 복사하는 연산은 이 원본에 대한 참조 카운트를 증가시키는 일만 진행
▪
사용자가 원본을 수정하는 연산을 요청할 때 프록시가 실제로 복사를 진행하여 사본이 별도의 값을 가지게 함
•
원본에 대한 참조자 수 감소
▪
해당 과정의 반복 속에 참조 카운트가 0이 되면 대상 삭제
7. 예시 코드
// Interface for the network API
interface NetworkAPI {
request(endpoint: string): Promise<any>;
}
// Implementation of the network API
class RealNetworkAPI implements NetworkAPI {
public async request(endpoint: string): Promise<any> {
console.log(`Making a network request to ${endpoint}`);
// Simulate network latency
await new Promise(resolve => setTimeout(resolve, 1000));
return { data: `Response from ${endpoint}` };
}
}
// Proxy class
class NetworkAPIProxy implements NetworkAPI {
private realNetworkAPI: RealNetworkAPI;
private cache: Map<string, any>;
constructor() {
this.realNetworkAPI = new RealNetworkAPI();
this.cache = new Map<string, any>();
}
public async request(endpoint: string): Promise<any> {
if (this.cache.has(endpoint)) {
console.log(`Returning cached data for ${endpoint}`);
return this.cache.get(endpoint);
} else {
const response = await this.realNetworkAPI.request(endpoint);
console.log(`Adding data to cache for ${endpoint}`);
this.cache.set(endpoint, response);
return response;
}
}
}
// Client code
async function fetchData(endpoint: string, api: NetworkAPI): Promise<void> {
const response = await api.request(endpoint);
console.log(response);
}
const networkAPI = new NetworkAPIProxy();
await fetchData("https://example.com/data", networkAPI);
await fetchData("https://example.com/data", networkAPI);
// Making a network request to https://example.com/data
// Adding data to cache for https://example.com/data
// { data: 'Response from https://example.com/data' }
// Returning cached data for https://example.com/data
// { data: 'Response from https://example.com/data' }
TypeScript
복사