The Proxy Pattern
Proxy 패턴은 간단한 객체로 복잡한 객체를 표현하고자 할 때 사용되어진다. 만약 어떤 객체를 생성하는 것이 시간적으로나 컴퓨터 자원적으로 비용이 많이 든다면 , Proxy는 실제적인 객체를 필요로 할 때까지 객체 생성을 연기하도록 할 것이다. 일반적으로 Proxy는 표현하고자 하는 객체와 같은 메소드를 갖고, 일단 객체가 로드되면, 그것은 Proxy에서 실제적인 객체의 메소드로 바뀌게 된다.
Proxy 가 유용하게 사용되어 질 수 있는 유용한 경우는 다음과 같다 :
- 커다란 이미지와 같은 객체가 로드하는데 시간이 많이 걸린다면 Proxy가 유용한다.
- 원격 머신에 객체가 있고 그 객체를 네트워크를 통하여 로드하는데 느릴 수 있고, 특히나 로드하는 동안 네트워크 상태가 절정이라면 Proxy가 유용하다.
- 객체가 바로 접근하는 것이 제한되어 있다면 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); } }
프로그램의 두 가지 상태는 아래의 그림처럼 설명될 수 있다.
##########0*##########1*
Copy-on-Write
또, proxy는 변경될 수도 있고, 변경되지 않을 수도 있는 커다란 객체들을 복사하는데에도 사용되어 질 수 있다. 마약 비싼 객체의 두 번째 인스턴스를 생성한다면, Proxy는 여전히 복사본을 만들 이유가 없다는 것을 결정할 수 있다. 간단하게 워본 객체를 사용하는 것이다. 그리고 나서, 만약 프로그램이 새로운 복사로 변경되었다면, Proxy가 원본 객체를 복사할 수 있고, 새로운 인스턴스로 변경되는 것을 만들 수 있다. 이것은 객체들이 인스턴스가 된 후 항상 변경하지 않을 때 시간과 공간을 크게 줄일 수 있게 한다.
'Development > 패턴자료' 카테고리의 다른 글
[펌] The State Pattern (0) | 2011.08.13 |
---|---|
[펌] The Singleton Pattern (0) | 2011.08.13 |
[펌] The Prototype Pattern (0) | 2011.08.13 |
[펌] The Observer Pattern (0) | 2011.08.13 |
[펌] The Memento Pattern (0) | 2011.08.13 |
안정적인 DNS서비스 DNSEver