자바 디자인 패턴 용어 사전
구조 패턴프록시 · 퍼사드

Proxy

실제 객체 대신 서서 접근을 제어하는 패턴. 퍼사드는 복잡한 하위 시스템을 단순한 창구로 감춘다.

실제 객체를 대신해 서서 접근을 제어하는 패턴.

interface Image { void display(); }

class RealImage implements Image {
    RealImage(String file) { loadFromDisk(file); }   // 생성이 비싸다
    public void display() { ... }
}

class ImageProxy implements Image {
    private RealImage real;
    private final String file;
    public void display() {
        if (real == null) real = new RealImage(file);   // 실제로 필요할 때 만든다
        real.display();
    }
}

종류

  • 가상 프록시 — 생성이 비싼 객체를 지연 생성한다 (ORM 의 지연 로딩)
  • 보호 프록시 — 권한을 확인하고 통과시킨다
  • 원격 프록시 — 네트워크 너머 객체를 로컬 객체처럼 보이게 한다 (RPC 스텁)
  • 캐싱 프록시 — 결과를 저장했다 재사용한다
  • 스마트 참조 — 참조 횟수를 세거나 부가 동작을 한다

프레임워크가 이 위에 서 있다

  • 트랜잭션·캐시·보안 애노테이션 → 프록시가 메서드를 가로채 부가 동작을 넣는다

  • ORM 의 지연 로딩 → 프록시 객체를 넣어 두고 실제 접근 시 조회한다

  • 원격 호출 스텁 → 로컬 호출처럼 보이는 프록시

  • "애노테이션 하나로 동작이 바뀌는" 마법의 정체가 대개 프록시다

그래서 따라오는 제약

프록시는 '바깥에서 들어오는 호출' 만 가로챈다

  • 같은 객체 안에서 자기 메서드를 부르면 프록시를 거치지 않는다
  • 애노테이션이 조용히 무시된다

또한 final 클래스·final 메서드·private 메서드는 감쌀 수 없다

Facade — 복잡한 것을 단순한 창구로

// 하위 시스템 여럿을 감춘다
class VideoConverter {
    public File convert(String file, String format) {
        VideoFile v = new VideoFile(file);
        Codec src = CodecFactory.extract(v);
        Codec dst = format.equals("mp4") ? new Mpeg4Codec() : new OggCodec();
        return BitrateReader.convert(v, src, dst);
    }
}
  • Proxy — 같은 인터페이스로 하나를 감싼다 — 접근 제어

  • Facade — 새 인터페이스로 여러 개를 감춘다 — 단순화

  • Adapter — 다른 인터페이스로 변환한다 — 호환

  • 셋 다 "감싼다" 이지만 목적이 각각 다르다

면접 함정

  • "Proxy는 성능 최적화용" → 지연 로딩은 한 종류일 뿐이다. 접근 제어가 본질이다.
  • "Facade를 두면 하위 시스템을 못 쓴다" → 감추는 것이지 막는 것이 아니다. 필요하면 직접 쓸 수 있다.

동적 프록시 — 런타임에 만든다

// 인터페이스만 있으면 구현을 런타임에 생성할 수 있다
Object proxy = Proxy.newProxyInstance(
    loader, new Class[]{Service.class},
    (p, method, args) -> {
        log.info("호출: " + method.getName());
        return method.invoke(target, args);
    });
  • JDK 동적 프록시 — 인터페이스 기반. 인터페이스가 있어야 한다

  • CGLIB — 클래스 상속 기반. 인터페이스가 없어도 된다

    • final 클래스·final 메서드는 못 감싼다
  • 프레임워크가 애노테이션을 처리하는 방식이 대개 이 둘 중 하나다

프록시인지 확인하는 법

System.out.println(bean.getClass());
// class com.example.OrderService$$SpringCGLIB$$0   ← 프록시다

Facade가 흔해지는 곳

  • 레거시 시스템 앞에 두는 새 API

  • 마이크로서비스 앞의 게이트웨이 (여러 서비스를 하나의 응답으로)

  • SDK 의 진입점 클래스

  • 주의: 퍼사드가 계속 커지면 God Object 가 된다

    • "창구" 이지 "모든 로직의 집합소" 가 아니다

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 구조 패턴 ② — 감추고, 공유하고, 대신한다