+TypeScript 예제
호출부는 IImage로 그리기를 요청하고, 프록시는 실제 객체를 언제 만들지 결정한다. 생성 지연 조건을 화면마다 반복하지 않으려고 접근 제어와 실제 그리기를 나눈다.
// 실제 객체와 대리 객체를 호출부가 같은 방식으로 쓰게 한다.
interface IImage { draw(): string; }
class RealImage implements IImage {
static created = 0;
constructor() { RealImage.created++; }
draw(): string { return "draw image"; }
}
// 생성 시점만 제어하고 실제 작업은 생성한 객체에 위임한다.
class ImageProxy implements IImage {
#image: RealImage | undefined;
draw(): string {
this.#image ??= new RealImage();
return this.#image.draw();
}
}
const image: IImage = new ImageProxy();
console.log(RealImage.created);
console.log(image.draw());
console.log(image.draw());
console.log("created: " + RealImage.created);
0
draw image
draw image
created: 1
TypeScript에서는 #image에 실제 객체를 보관해 C# Lazy<RealImage>의 지연 생성 역할을 표현했다. draw()의 결과를 캐시하는 것이 아니라 객체를 재사용하며, 실제 이미지 파일은 읽지 않는다.
남용하면 생기는 문제
프록시가 파일·네트워크 접근이나 재시도를 숨기면 겉보기에는 같은 메서드여도 지연 시간과 실패 방식이 달라진다. 호출부가 동기 계산이라고 믿게 둔 채 원격 호출을 끼워 넣으면 투명한 대리라는 장점이 오히려 장애 원인을 가린다. 실제 I/O를 넣을 때는 취소·실패·실행 횟수 계약을 함께 드러내야 한다.