프록시(Proxy) 패턴 이해를 위한 쉬운 예제

Choizz·2023년 1월 30일
0

디자인 패턴

목록 보기
1/8
post-thumbnail

이번 포스팅은 프록시 패턴에 대해 알아볼 것이다. 프록시(Proxy)는 '대리자'라는 의미이다.

즉, 프록시 패턴은 실제 객체를 대리하는 프록시 객체를 사용해서 실체 객체의 생성이나 접근을 제어할 수 있도록 해 주는 패턴이다.

쉽게 생각하면, 그냥 중간에 프록시라는 대리인이 껴있어서 그 대리인이 접근을 통제한다고 생각하면 된다.


이미지 캐싱을 할 경우를 가정해서 생각을 해보자.

어떤 사이트에 들어간다고 가정을 했을 때, 이미지 4개가 먼저 보여진다고 가정해보자.
이럴 경우 프록시 객체를 사용해서 맨 처음 사이트를 방문 후 다음에 다시 방문할 때, 먼저 보여지는 4개의 이미지를 캐싱을 해두면 이미지 객체에 도달하지 않고, 프록시 객체에서 이미지를 출력할 수 있다.


프록시 패턴

  • Image 인터페이스를 만들었다.
public interface Image {
	void print();
}
  • RealImage객체는 Image 인터페이스를 구현한다.
    • RealImage객체가 생성될 때, Image 객체 4개가 생성되고 그것을 STORE에 저장한다.
public class RealImage implements Image {

	public static List<Image> STORE = new ArrayList<>();

	public RealImage() {
		STORE.add(new Image1());
		STORE.add(new Image2());
		STORE.add(new Image3());
		STORE.add(new Image4());
	}

	@Override
	public void print() {
		for (Image image : STORE) {
			image.print();
		}
	}
}
  • 프록시 객체를 생성한다.
  • 프록시 객체 또한 Image 인터페이스를 구현하게 한다. Image 인터페이스를 구현한다. 이렇게 함으로써 Site 객체는 Proxy 객체가 사용되는지, RealImage 객체가 사용되는지 알 수 없게 한다.
    • 만약 STORE에 저장된 image객체가 없다면 RealImage객체를 생성한 후 출력한다. 즉, Proxy 객체가 RealImage 객체에 의존하게 된다.
    • 만약 STORE에 저장된 이미지가 있다면 RealImage 객체를 생성하지 않고 바로 이미지를 출력한다.
public class Proxy implements Image {

	@Override
	public void print() {
		if (RealImage.STORE.isEmpty()) { //저장소 확인
			System.out.println("RealImage 객체 생성 ");
			RealImage realImage = new RealImage(); // 프록시 객체가 진짜 객체에 의존하게 된다.
			realImage.print();
		} else {
			System.out.println("프록시");
			for (Image image : RealImage.STORE) {
				image.print();
			}
		}
	}
}
  • Site 객체는 프록시 객체를 받아서 사용한다. Site 객체는 Image 타입의 객체를 받기 때문에 Proxy 객체가 들어오는지 RealImage 객체가 들어오는지 알 수 없다.
  • draw()를 통해 이미지를 출력한다.
public class Site {

	private Image proxy;

	public Site(Image proxy) {
		this.proxy = proxy;
	}

	public void draw(){
		long startTime = System.currentTimeMillis(); // 시간 측정
		proxy.print(); //프록시에게 이미지 출력을 위임.
		long endTime = System.currentTimeMillis();
		long resultTime = endTime - startTime;
		System.out.println("==========="+resultTime);
	}
}
  • Site -> Proxy -> RealImage로 의존하게 된다.
  • 결과를 보면 처음 사이트를 방문했을 경우, RealImage 객체에서 이미지를 출력하고, 1.xxms가 걸린다.
  • 다시 방문할 경우 프록시 객체에서 이미지를 출력하고, 0.xxms가 걸리는 것을 알 수 있다. 이것은 프록시 객체에서 진짜 객체에 대한 접근을 차단하고 생성을 제한했다고도 볼 수 있다.
public class Main {
	public static void main(String[] args) {
	
		Proxy proxy = new Proxy(); // 프록시 객체에 실제 객체 주입
		Site site = new Site(proxy); //클라이언트 객체에는 프록시 객체 주입

		//프록시에서 이미지 출력 x
		site.draw();

		//프록시에 이미지 출력
		site.draw();
	}
}

결과

이미지 1 출력
이미지 2 출력
이미지 3 출력
이미지 4 출력
===========1
프록시
이미지 1 출력
이미지 2 출력
이미지 3 출력
이미지 4 출력
===========0

정리

  • 위의 예는 프록시를 사용해서 캐싱을 한 경우를 살펴 보았다.
  • 객체의 생성을 제한하고 필요할 때 객체를 생성해주는 프록시를 가상 프록시(virtual proxy)라고 한다.
  • 가상 프록시 외에도 접근 권한이 있는 경우에만 실체 객체의 메서드를 실행시켜 주는보호 프록시,
    다른 프로세스에 존재하는 객체에 접근할 때 사용되는 원격 프록시 등이 있다.
  • 또한 인터페이스를 사용하지 않고 바로 상속을 받아서 프록시로 사용하는 방법도 있다. 하지만 상속을 받는 경우, 상위 객체가 항상 생성되기 때문에 가상 프록시로 쓰기에는 적합하지 않다.

Reference

profile
집중

0개의 댓글