프로그래밍
프록시 패턴
수박수박좋다
2024. 7. 19. 10:14
반응형
프록시 패턴
원본 객체에 접근해 사용하는 것이 아닌 프록시를 통해 원본 객체를 사용하는 방법
장점
- 접근 제어: 클라이언트가 원본 객체에 직접 접근하지 않도록 제어
- 지연 초기화: 무거운 클래스를 바로 인스턴스화하지 않고 지연시켜 성능 최적화 가능
- 캐싱: 자주 사용하는 데이터를 캐싱하여 성능 향상
- 원격 서비스 로컬 실행: 원격 서비스를 로컬에서 실행하여 네트워크 비용 절감
- 유효성 검사: 데이터 유효성 검사를 통해 원본 객체 보호
- 로깅: 요청과 응답에 대한 로깅 기능 제공
단점
- 응답 지연: 프록시를 통한 추가 작업으로 인해 응답이 늦어질 수 있음
- 복잡성 증가: 클래스를 새로 도입해야 하므로 코드가 복잡해질 수 있음
예제
/**
* Subject 인터페이스는 RealSubject와 Proxy 모두를 위한 공통 작업을 선언합니다.
* 클라이언트가 이 인터페이스를 사용하여 RealSubject와 작업하는 한,
* 실제 주체 대신 프록시를 전달할 수 있습니다.
*/
interface Subject {
request(): void;
}
/**
* RealSubject는 일부 핵심 비즈니스 로직을 포함합니다. 일반적으로 RealSubjects는
* 입력 데이터를 수정하는 등 유용한 작업을 수행할 수 있지만 매우 느리거나 민감할 수 있습니다.
* Proxy는 RealSubject 코드의 변경 없이 이러한 문제를 해결할 수 있습니다.
*/
class RealSubject implements Subject {
public request(): void {
console.log('RealSubject: Handling request.');
}
}
/**
* Proxy는 RealSubject와 동일한 인터페이스를 가집니다.
*/
class Proxy implements Subject {
private realSubject: RealSubject;
/**
* Proxy는 RealSubject 클래스의 객체에 대한 참조를 유지합니다.
* 이는 지연 로드되거나 클라이언트에 의해 Proxy로 전달될 수 있습니다.
*/
constructor(realSubject: RealSubject) {
this.realSubject = realSubject;
}
/**
* Proxy 패턴의 가장 일반적인 응용 프로그램은 지연 로딩, 캐싱,
* 액세스 제어, 로깅 등입니다. Proxy는 이러한 작업 중 하나를 수행한 다음,
* 결과에 따라 연결된 RealSubject 객체에서 동일한 메서드의 실행을 전달할 수 있습니다.
*/
public request(): void {
if (this.checkAccess()) {
this.realSubject.request();
this.logAccess();
}
}
private checkAccess(): boolean {
// 여기에 실제 검사 로직이 들어가야 합니다.
console.log('Proxy: Checking access prior to firing a real request.');
return true;
}
private logAccess(): void {
console.log('Proxy: Logging the time of request.');
}
}
/**
* 클라이언트 코드는 모든 객체(주제 및 프록시)를 Subject 인터페이스를 통해
* 작업해야 실제 주제와 프록시 모두를 지원할 수 있습니다. 그러나 실제로는
* 대부분의 클라이언트가 실제 주체와 직접 작업합니다. 이 경우 패턴을 더 쉽게
* 구현하기 위해 프록시를 실제 주체 클래스에서 확장할 수 있습니다.
*/
function clientCode(subject: Subject) {
// ...
subject.request();
// ...
}
console.log('Client: Executing the client code with a real subject:');
const realSubject = new RealSubject();
clientCode(realSubject);
console.log('');
console.log('Client: Executing the same client code with a proxy:');
const proxy = new Proxy(realSubject);
clientCode(proxy);
- 프록시 패턴은 원본 객체의 호출을 가로채 부가 작업을 추가하는데 유용
- 클라이언트는 원본과 동일한 인터페이스로 구현된 객체를 호출하기에 큰 차이를 알지 못함
- JavaScript에는
Proxy
라는 내장 객체가 있어 동일 기능을 짧게 구현 가능
내장 객체 Proxy 예제
class Subject {
request() {
throw new Error("This method should be overridden.");
}
}
class RealSubject extends Subject {
request() {
console.log('RealSubject: Handling request.');
}
}
/**
* JavaScript Proxy 객체를 사용하여 동일한 인터페이스를 가진 Proxy 클래스를 생성
*/
const handler = {
get: function(target, prop, receiver) {
if (prop === 'request') {
return function() {
if (proxy.checkAccess()) {
target[prop]();
proxy.logAccess();
}
};
}
return Reflect.get(...arguments);
}
};
const realSubject = new RealSubject();
const proxy = new Proxy(realSubject, handler);
// Proxy 객체의 메서드들을 추가로 정의
proxy.checkAccess = function() {
console.log('Proxy: Checking access prior to firing a real request.');
return true;
};
proxy.logAccess = function() {
console.log('Proxy: Logging the time of request.');
};
/**
* 클라이언트 코드는 모든 객체(주제 및 프록시)를 Subject 인터페이스를 통해
* 작업해야 실제 주제와 프록시 모두를 지원할 수 있습니다. 그러나 실제로는
* 대부분의 클라이언트가 실제 주체와 직접 작업합니다. 이 경우 패턴을 더 쉽게
* 구현하기 위해 프록시를 실제 주체 클래스에서 확장할 수 있습니다.
*/
function clientCode(subject) {
// ...
subject.request();
// ...
}
console.log('Client: Executing the client code with a real subject:');
clientCode(realSubject);
console.log('');
console.log('Client: Executing the same client code with a proxy:');
clientCode(proxy);
- 위 예제는 JavaScript의
Proxy
객체를 사용하여 프록시 패턴을 구현 handler
객체의get
트랩을 사용하여request
메서드를 가로채고 접근 제어와 로깅 기능 추가Proxy
객체는checkAccess
와logAccess
메서드를 정의하여 이러한 기능 구현
JavaScript Proxy 객체
- Proxy 객체: JavaScript에서 제공하는 내장 객체로, 기본 작업(속성 접근, 할당, 함수 호출 등)을 가로채고 재정의할 수 있음
- 핸들러(handler): 트랩(trap)이라는 함수를 정의하는 객체로, 특정 작업을 가로챌 때 실행되는 메서드들로 구성
- 타겟(target): Proxy가 감싸는 객체로, 기본 작업이 수행되는 실제 객체
Proxy 객체 예제
const target = {
message1: "hello",
message2: "everyone"
};
const handler = {
get: function(target, prop, receiver) {
if (prop === 'message2') {
return 'world';
}
return Reflect.get(...arguments);
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.message1); // hello
console.log(proxy.message2); // world
target
객체는 원본 객체handler
객체는get
트랩을 정의하여 속성 접근을 가로채고 재정의Proxy
객체는target
과handler
를 결합하여 새로운 프록시 객체 생성proxy.message2
접근 시handler
의get
트랩이 실행되어 'world'를 반환- JavaScript
Proxy
객체는 프록시 패턴을 간결하게 구현할 수 있게 해줌 - 다양한 트랩을 통해 속성 정의, 삭제, 함수 호출 등 여러 작업을 가로채고 재정의 가능
- 성능 최적화, 접근 제어, 로깅 등 다양한 활용 사례 존재
반응형