본문 바로가기

Dev.../패턴자료

The Proxy Pattern

The Proxy Pattern

    Proxy 패턴은 간단한 객체로 복잡한 객체를 표현하고자 할 때 사용되어진다. 만약 어떤 객체를 생성하는 것이 시간적으로나 컴퓨터 자원적으로 비용이 많이 든다면 , Proxy는 실제적인 객체를 필요로 할 때까지 객체 생성을 연기하도록 할 것이다.  일반적으로 Proxy는 표현하고자 하는 객체와 같은 메소드를 갖고, 일단 객체가 로드되면, 그것은 Proxy에서 실제적인 객체의 메소드로 바뀌게 된다. 

    Proxy 가 유용하게 사용되어 질 수 있는 유용한 경우는 다음과 같다 :      
  1. 커다란 이미지와 같은 객체가 로드하는데 시간이 많이 걸린다면 Proxy가 유용한다.
  2. 원격 머신에 객체가 있고 그 객체를 네트워크를 통하여 로드하는데 느릴 수 있고, 특히나 로드하는 동안 네트워크 상태가 절정이라면 Proxy가 유용하다.
  3. 객체가 바로 접근하는 것이 제한되어 있다면 Proxy는 사용자의 접근허용을 검증할 수 있다.
    Proxy 들은 또한 객체의 인스턴스 요청과 실제적으로 접근하는 것이 필요한가 사이를 구별하는데 사용되어 질 수 있다. 예를 들어 프로그램 초기화는 바로 사용되어 지지 않는 객체들을 설치할 수 있다. 이 경우에, proxy는 필요할 때만 실제적인 객체를 로드할 수 있다. 

    커다란 이미지를 로드하고 나타내어야 할 필요가 있는 프로그램의 경우를 고려해 보자.  프로그램이 시작될 때 이미지가 스크린에 정확하게 배치될 수 있도록 나타내 줄 수 있는 어떤 필요한 조치를 해야 한다.그러나 실제적인 이미지의 디스플레이는 이미지가 완벽하게 로드될 때까지 지연된다. 이것은 이미지가 이용되기 전에 이미지 주위에 텍스트를  배치하는 워드프로세서나 웹브라우저에서는 상당히 중요하다. 

    이미지 proxy는 이미지를 주목할 수 있고 배경에 이미지를 로딩할 수 있다. 반면에 간단한 사각형이나 다른 기호 같은 것은 그려줄 수 있다. proxy는 paint 요청이 있을 때 까지 이미지를 로딩을 지연하고, paint가 요청될 때만 로딩하게 할 수 있다.

Sample Code

    예제 프로그램에서, 우리는 이미지가 로딩 했을 때 JPanel 상에 이미지를 나타내는 프로그램을 작성하였다. 이미지를 직접적으로 로딩하는 것 보다, 우리는 로딩을 연기하고 이미지가 완벽하게 로딩될 때 까지 이미지 영역에 사각형을 그려주는 ImageProxy라 불리는 클래스를 사용할 것이다. 
	public class ProxyDisplay extends JxFrame {	public ProxyDisplay() {		super("Display proxied image");		JPanel p = new JPanel();		getContentPane().add(p);		p.setLayout(new BorderLayout());		ImageProxy image = new ImageProxy("elliott.jpg", 321, 271);		p.add("Center", image);		p.add("North", new Label("    "));		p.add("West", new Label("  "));		setSize(370, 350);		setVisible(true);	}
    단지 하나의 이미지를 포함할 수 있는 ImageProxy의 인스턴스를 생성하였고, 실제적인 이미지로써 JPanel을 추가하였다.

    ImageProxy 클래스는 이미지 로딩을 set up 하고, 생성자 내부에서 로딩 처리를 하기 위해 MediaTracker object를 생성하였다.
	class ImageProxy extends JPanel implements Runnable {	int height, width;	MediaTracker tracker;	Image img;	JFrame frame;	Thread imageCheck;        //to monitor loading		//------------------------------------		public ImageProxy(String filename, int w, int h) {		height = h;		width = w;				tracker = new MediaTracker(this);		img = Toolkit.getDefaultToolkit().getImage(filename);		tracker.addImage(img, 0);     //watch for image loading				imageCheck = new Thread(this);		imageCheck.start();           //start 2nd thread monitor				//this begins actual image loading		try {			tracker.waitForID(0,1);		}		catch(InterruptedException e){		}}
    MediaTracher 의 weightForID 메소드는 실제적인 로딩 초기화를 한다. 이 경우에, 우리는 프로그램이 지연되는 최소로 하기 위해 최소 기다리는 시간을 1 msec로 입력하였다.

    생성자는 또한 2~3 밀리세컨드에서 로딩 상태를 체크하는 imageCheck 쓰레드를 분리하여 생성하였고, 쓰레드 작동을 시작하였다.
	public void run() {	//this thread monitors image loading	//and repaints when done	//the 1000 msec is artifically long	//to allow demo to display with delay		try {		Thread.sleep(1000);		while(! tracker.checkID(0))		Thread.sleep(1000);	}		catch(Exception e){}		repaint();}
    마지막으로, Proxy는 JPanel 컴포넌트로부터 파생되었으므로, 본질적으로 paint 메소드를 갖는다. 이 메소드에서, 우리는 이미지 로딩되지 않았다면 사각형을 그려준다. 만약 이미지가 로딩되었다면, 우리는 사각형을 지워주고 대신 이미지를 그릴 것이다.  
	public void paintComponent(Graphics g) {	super.paintComponent(g);	if (tracker.checkID(0)) {		height = img.getHeight(frame);   //get height		width = img.getWidth(frame);     //and width				g.setColor(Color.lightGray);     //erase box		g.fillRect(0,0, width, height);		g.drawImage(img, 0, 0, this);   //draw loaded image	}	else {		//draw box outlining image if not loaded yet		g.setColor(Color.black);		g.drawRect(1, 1, width-2, height-2);	}}

    프로그램의 두 가지 상태는 아래의 그림처럼 설명될 수 있다.

       

Copy-on-Write

또, proxy는 변경될 수도 있고, 변경되지 않을 수도 있는 커다란 객체들을 복사하는데에도 사용되어 질 수 있다. 마약 비싼 객체의 두 번째 인스턴스를 생성한다면, Proxy는 여전히 복사본을 만들 이유가 없다는 것을 결정할 수 있다. 간단하게 워본 객체를 사용하는 것이다. 그리고 나서, 만약 프로그램이 새로운 복사로 변경되었다면, Proxy가 원본 객체를 복사할 수 있고, 새로운 인스턴스로 변경되는 것을 만들 수 있다. 이것은 객체들이 인스턴스가 된 후 항상 변경하지 않을 때 시간과 공간을 크게 줄일 수 있게 한다. 

'Dev... > 패턴자료' 카테고리의 다른 글

The Flyweight Pattern  (0) 2005.02.28
The Facade Pattern  (0) 2005.02.28
The Composite Pattern  (0) 2005.02.28
The Adapter Pattern  (0) 2005.02.28
Structural Patterns  (0) 2005.02.28