Proxy pattern


** 출처
*    Printable interface, Printer class, PrinterProxy class
*    => [java 언어로 배우는 디자인패턴 입문 / yuki hiroshi / 영진닷컴]에서 발췌한 것에 주석을 단 것입니다.
*/

목차
- proxy pattern class diagram
- ProxyPatternTest (test code)
- Printable interface
- Printer class
- PrinterProxy class

===============================================================================
proxy pattern class diagram
===============================================================================



===============================================================================
ProxyPatternTest
===============================================================================

package com.hdju.patterns;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.junit.Before;
import org.junit.Test;
public class ProxyPatternTest {
 private String printer1;
 private String printer2;
 private String printer3;
 private String message;
 @Before
 public void setUp() throws Exception {
  printer1 = "first printer";
  printer2 = "second printer";
  printer3 = "third printer";
  message = "printer test";
 }
 /*
  * 아래 예제는 virtual proxy 임.
  */
 @Test
 public void printProxyTest() {
  Printable printer = new PrinterProxy();
  printer.setPrinterName(printer1);
  assertThat("=== " + printer1 + " ===" + printer1 + " | printer test",
    is(printer.print(message)));
  /*
   * 프린터 네임을 set해도 프린터 이름이 변경되지 않음을 보여준것은
   * 객체를 새로 생성한 것이 아닌것을 보여주기 위한 의도된 것임.
   * Printer클래스의 print() 메소드 참조할 것.
   */
  printer.setPrinterName(printer2);
  assertThat("=== " + printer1 + " ===" + printer1 + " | printer test",
    is(printer.print(message)));
  printer.setPrinterName(printer3);
  assertThat("=== " + printer1 + " ===" + printer1 + " | printer test",
    is(printer.print(message)));
  // 총 수행시간 5s
 }
 @Test
 public void printNoneProxyTest() {
  // Printer 클래스를 직접 이용할 경우 항상 새로 객체를 생성하므로 테스트 코드를 변경함
  Printable first = new Printer();
  first.setPrinterName(printer1);
  assertThat("=== " + printer1 + " ===" + printer1 + " | printer test",
    is(first.print(message)));
  Printable second = new Printer();
  second.setPrinterName(printer2);
  assertThat("=== " + printer2 + " ===" + printer2 + " | printer test",
    is(second.print(message)));
  Printable third = new Printer();
  third.setPrinterName(printer3);
  assertThat("=== " + printer3 + " ===" + printer3 + " | printer test",
    is(third.print(message)));
  // 총 수행시간 15s
 }
 /**
  * Proxy 패턴은 초기 로딩이 많이 걸리는 경우 사용하면 속도 개선이 있다.
  */

===============================================================================
Printable interface
===============================================================================

package com.hdju.patterns;
public interface Printable {
 public void setPrinterName(String printerName);
 public String getPrinterName();
 public String print(String message);
}

===============================================================================
Printer class
===============================================================================

package com.hdju.patterns;
public class Printer implements Printable {
 private String name;
 public Printer() {
  heavyJob("Printer 인스턴스를 생성 중");
 }
 public Printer(String name) {
  this.name = name;
  heavyJob("Printer의 인스턴스 (" + name + ") 을 생성 중");
 }
 @Override
 public void setPrinterName(String printerName) {
  this.name = printerName;
 }
 @Override
 public String getPrinterName() {
  return this.name;
 }
 @Override
 public String print(String message) {
  String printResult = "=== " + name + " ===" + name;
  return printResult + " | " + message;
 }
 private void heavyJob(String jobSubject) {
  System.out.println(jobSubject);
  for (int i = 0; i < 5; i++) {
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
   }
   System.out.print(".");
  }
  System.out.println("완료.");
 }
}


===============================================================================
PrinterProxy class
===============================================================================

package com.hdju.patterns;
public class PrinterProxy implements Printable {
 private String name;
 private Printer real;
 private String classname;
 public PrinterProxy() {
 }
 public PrinterProxy(String name) {
  this.name = name;
 }
 public PrinterProxy(String name, String classname) {
  this.name = name;
  this.classname = name;
 }
 @Override
 public void setPrinterName(String printerName) {
  this.name = printerName;
 }
 @Override
 public String getPrinterName() {
  return this.name;
 }
 @Override
 public String print(String message) {
  realize();
  return real.print(message);
 }
 /*
  * synchronized를 사용하지 않을 경우 스레드 세이프하지 않다.
  */
 private synchronized void realize() {
  if (real == null) {
   real = new Printer(name);
   /*
    * REFACTORING point : Printer 클래스가 소스에 직접 지정되어있다. 이를 해결하기 위해
    * classname을 별도로 입력받아 사용하도록 하면 커플링을 줄일수 있다.
    *
    * real = (Printable)Class.forName(classname).newInstance();
    * real.setPrinterName(name);
    *
    * (예외처리 생략)
    */
  }
 }
}

===============================================================================
===============================================================================

댓글

이 블로그의 인기 게시물

Session 대신 JWT를 사용하는 이유

VSCode에서의 VIM 단축키와 키보드 구매 가이드

우분투에서 테스트링크(testlink)와 맨티스(mantis)로 테스팅 서버 구성하기