개요

  Proxy(대리인) 패턴은 어떤 업무를 처리 할 때 대리인이 대신 처리할 수 있는 업무는 대리인이 처리하고 직접 처리해야 할 업무만 본인이 직접 처리하도록 하는 패턴이다.

 업무 요청은 늘 대리인이 받고 대리인이 처리할 수 있는 업무는 처리하고 본인이 직접 처리해야 할 경우만 본인을 호출해 업무를 전달한다. 여기서 본인은 대리인의 존재 조차도 몰라도 된다.

 

역할

Subject 역할

 Proxy 역할과 RealSubject 역할을 동일시 하기 위한 인터페이스. 사용자는 Subject 역할을 통해 Proxy역할과 RealSubject 역할을 구분하지 않고 동일시 사용할 수 있다. 예제에서는 Printable 인터페이스.

 

Proxy 역할

 Client의 요청을 자신(대리인)이 가능한 범위만큼 처리하고, 자신(대리인)이 처리할 수 없다면 본인에게 처리를 넘기는 역할을 한다. 예제에서는 PrinterProxy 클래스.

 

RealSubject 역할

 Proxy역할(대리인)이 해결할 수 없는 요청을 넘겨받아 처리하는 본인 역할. 예제에서는 Printer 클래스.

 

Client 역할

 Proxy 패턴을 이용하는 역할. 업무를 Proxy에게 요청한다. 예제에서는 ProxyTester 클래스.

 

 

이득 및 유의사항

 프로그램에서 많은 자원이 소요되는 무거운 작업은 사실 뻔한데, 대표적인 것이 프로그램 기동과 그에 필요한 초기화 작업이다. Proxy패턴을 적용해서 기동시 실제로 바로 필요한 초기화 작업만 수행하면, 빠른 기동으로 프로그램 사용자의 불편을 줄일 수 있다.

 대리인과 본인을 굳이 분리해야 할 필요가 있을까 생각할 수도 있다. 지연평가(요청시 인스턴스 생성) 기능을 사용한다면 굳이 분리할 필요가 없지 않을까 싶을 수 있다. 하지만 RealSubject 역할과 Proxy 역할을 분리해서 프로그램을 구성하면 각 기능에 따라 모듈화가 되고 개별적인 수정과 변경이 더 자유로워 진다.

 흔히 Proxy라는 단어를 쉽게 접하는 것이 http proxy 서버일 텐데, 그 원리도 proxy패턴과 다르지 않다. 어떤 일을 클라이언트가 요청할 때 이를 실제로 먼저 받는 것은 proxy서버이고 자신이 처리할 수 있는(캐싱되어 있는) 요청이면 자신이 처리하고 아닐 경우만 외부에 요청을 전달하기 때문에 proxy서버는 proxy 역할, 외부 서버는 RealSubject 역할이 되는 것이다.

 

 

예제 코드

//Subject역할
package proxy;

public interface Printable {
	public abstract void setPrinterName(String name);
	public abstract String getPrinterName();
	public abstract void print(String string);
}


//Proxy 역할
package proxy;

public class PrinterProxy implements Printable{
	private String name;
	private Printer real;
	public PrinterProxy() {
		
	}
	
	public PrinterProxy(String name) {
		this.name = name;
	}
	
	

	@Override
	public synchronized void setPrinterName(String name) {
		if(real != null) {
			real.setPrinterName(name);
		}
		this.name = name;
	}

	@Override
	public String getPrinterName() {
		return name;
	}

	@Override
	public void print(String string) {
		realize();
		real.print(string);
	}
	
	private synchronized void realize() {
		if(real == null) {
			real = new Printer(name);
		}
	}
	
	
}


//RealSubject 역할
package proxy;

public class Printer implements Printable{

	private String name;
	
	public Printer() {
		heavyJob("Printer 인스턴스 생성 중");
	}
	
	public Printer(String name) {
		this.name = name;
		heavyJob("Printer 인스턴스 생성 중");
	}
	
	@Override
	public void setPrinterName(String name) {
		this.name = name;
	}

	@Override
	public String getPrinterName() {
		return name;
	}

	@Override
	public void print(String string) {
		System.out.println("===" + name + "===");
		System.out.println(string);
	}
	
	private void heavyJob(String msg) {
		System.out.println(msg);
		for(int i=0; i<5; i++) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
			}
			System.out.println(".");
		}
		System.out.println("완료.");
	}
		
}

//Client 역할
package proxy;

public class ProxyTester {
	public static void main(String[] args) {
		Printable p = new PrinterProxy("Alice");
		System.out.println("현재 이름은 "+p.getPrinterName()+"입니다.");
		p.setPrinterName("BoB");
		System.out.println("현재 이름은 " + p.getPrinterName()+"입니다.");
		p.print("Hello, world");
	}
}

'디자인 패턴' 카테고리의 다른 글

23. Interpreter 패턴  (0) 2021.02.15
20. Flyweight 패턴  (0) 2021.01.05
18. Memento 패턴  (0) 2020.12.30
17. Observer 패턴  (0) 2020.12.29
16. Mediator 패턴  (0) 2020.12.28

+ Recent posts