'전체 글'에 해당되는 글 678건

  1. 2011.08.13 [펌] The State Pattern
  2. 2011.08.13 [펌] The Singleton Pattern
  3. 2011.08.13 [펌] The Proxy Pattern
  4. 2011.08.13 [펌] The Prototype Pattern

The State Pattern

    State 패턴은 관련된 다수의 클래스들 사이에서 대체할 수 있는 하나의 포괄적인 클래스를 갖고자 하고 현재 포함된 클래스를 호출하는 메소드를 전달하고자 할 때 이용된다. 디자인 패턴은 클래스를 바꾸기 위해 나타나는 포괄적인 객체와 같은 식으로 내부의 클래스들 사이를 대체하는데 State 패턴을 제안하였다. 자바에서는 조금 과장되었지만 실제적인 목적은 클래스들이 의미 있게 변경될 수 있도록 하는데 있다.

    많은 프로그래머들은 약간 차이가 있는 계산이나 클래스에 전달된 아규먼트들을 토대로 한 다른 정보를 보여주는 것을 수행하는 클래스를 생성한 경험이 있다. 이것은 종종 수행해야 할 행위를 결정짓기 위해 클래스 내부에 switch 나 if-else 와 같은 문장의 종류를 이끌게 한다. 그것은 State 패턴이 대체하는 것을 찾는 안 좋은 방법이다.

Sample Code

    Memento 클래스를 위하여 개발했던 것과 유사한 드로잉 프로그램의 경우를 고려해 보자. 프로그램은 Select, Rectangle, Fill, Circle 와 Clear를 위한 툴바를  갖게 될 것이다.

        ##########0*

    버튼 각각은 선택되고 화면에서 마우스를 클릭하거나 드래그 할 때  다른 일을 한다. 그러므로 그래픽 편집기의 상태는 프로그램이 진행되는 행위에 영향을 준다. 이것이 State 패턴을 이용한 몇 가지 설계를 제안한다.

    처음에는 우리의 프로그램을 5개의 명령 버튼들의 행동을 관리 하는 Mediator를 갖는 아래와 같은 프로그램을  설계할 수 있다.

        ##########1*

    그러나 처음의 설계는 Mediator에서 프로그램의 상태를 유지하는 전체적인 부하를 두게 되고, Mediator의 중요 목적은 다양한 컨트롤들 사이에서 활동들을 조정하는 것이다. 버튼들의 상태와 Mediator 내에서 요구되는 마우스의 활동을 유지하는 것은 프로그램을 읽고 유지하는 것을 어렵게 하는 if 나 switch 를 유도하게 되어 과도하게 복잡하게 만든다.

    게다가 거대한 조건문 집단은 각 Mediator가 mouseUp, mouseDrag, rightClick 등과  같은 해석하는 동작에 대해서 반복해야만 할 수도 있다. 이것이 프로그램을 일기 어렵게 하고 유지하는 걸 어렵게 만든다.

    대신, 각 버튼들에 대해서 기대되는 행위를 분석해 보자 :
  1. Pick 버튼이 선택되었다면 드로잉 원소 내부에서의 clicking은  하이라이트 되거나 "handles"로 나타날 수 있다. 마우스가 드래그 되고 드로잉 원소가 이미 선택되었다면 그 원소는 화면상에서 움직일 수 있다.
     
  2. Rect 버튼이 선택되면 화면상에 clicking은 새로운 사각형 드로잉 원소를 생성할 수 있게 한다
     
  3. Fill 버튼이 선택되어 있고 드로잉 원소가 이미 선택되어 있으면, 그 원소는 현재 색으로 채워질 것이다. 만약 드로잉 선택되어 있지 않으면 드로잉 원소 내부를 클릭할 때 현재 색으로 채울 것이다.
     
  4. Circle 버튼이 선택되었다면 화면상에 클릭은 새로운 원 원소를 생성할 것이다.
     
  5. Clear 버튼이 선택되었다면 모든 드로잉 원소는 제거될 것이다.

    우리가 조사한 몇 가지 동작들 사이에는 몇 가지 공통적인 맥락이 있다. 그런 것들 중 네 가지는 마우스 클릭을 이용한다. 하나는 마우스 드래그 이벤트를 사용한다. 그러므로 우리는 실제로 버튼이 현재 선택되었는지를 토대로 이러한 이벤트를 다시 돌릴 수 있도록 하는 시스템을 만들고자 한다.
   
    마우스 동작을 조정하는 State 객체를 만들어 보자:


public class State {
	public void mouseDown(int x, int y){}
	public void mouseUp(int x, int y){}
	public void mouseDrag(int x, int y){}
}
    우리는 나중에 필요할 지도 모르기 때문에 mouseUp 이벤트를 포함할 것이다. 이러한 이벤트 모두의 필요성을  설명한 적이 없기 때문에 추상의 base 클래스를 생성하는 것 보다 메소드가 비어 있는 base 클래스를 만들 것이다. 그리고 나서 Pick, Rect, Circle 과 Fill을 위해 State 클래스로부터 4개를 파생시켜 생성할 것이고 현재 상태를 정하는 StateManager 클래스에 모두를 인스턴스로 넣고 state 객체상의 메소드들을 실행할 것이다. 디자인 패턴에서 StateManager 클래스는 Context로 참조된다. 이 객체는 아래와 같이 설명된다 :

        ##########2*

    전형적인 State 객체는 간단히 특별하게 조정해야 하는 이벤트 메소드들을 재정의한다. 

public class RectState extends State {
	private Mediator med;     //save the Mediator here
	
	public RectState(Mediator md) {
		med = md;
	}
	
	//create a new Rectangle where mode clicks
	public void mouseDown(int x, int y) {
		med.addDrawing(new visRectangle(x, y));
	}
}
    RectState 객체는 간단하게 Mediator에게 드로잉 목록에 사각형 드로잉을 추가할 것을 알려준다. 유사하게, Circle state 객체도 Mediator에게 드로잉 목록에 circle을 추가하도록 알려준다 :

public class CircleState extends State {
	private Mediator med;        //save Mediator
	
	public CircleState(Mediator md) {
		med = md;
	}
	
	//Draw circle where mouse clicks
	public void mouseDown(int x, int y) {
		med.addDrawing(new visCircle(x, y));
	}
}
    우리는 다음 두 가지 행동에 대해 정의를 했기 때문에 Fill 버튼은 교묘한 버튼이다.
  1. 이미 선택된 객체가 있다면 그것을 채워라
     
  2. 객체 내부에서 마우스가 클릭되면 그 객체를 채워라

    이러한 작업을 수행하기 위해 우리는 base State 클래스에 select 메소드를 추가하는 것이 필요하다. 이 메소드는 각각의 툴 버튼이 선택되면 호출되어 진다 :


public class State {
	public void mouseDown(int x, int y){}
	public void mouseUp(int x, int y){}
	public void mouseDrag(int x, int y){}
	public void select(Drawing d, Color c){}
}
 드로잉 아규먼트는 현재 선택된 드로잉이나 선택되지 않았다면 null이고 색은 현재 채워진 색이다. 이 프로그램에서 우리는 임으로 채워지는 색을 빨강색으로 정하였다 :

public class FillState extends State {
	private Mediator med;   //save Mediator
	private Color color;    //save current color
	
	public FillState(Mediator md) {
		med = md;
	}
	
	//Fill drawing if selected
	public void select(Drawing d, Color c) {
		color = c;
		
		if(d!= null) {
			d.setFill(c);  //fill that drawing
		}
	}
	
	//Fill drawing if you click inside one
	public void mouseDown(int x, int y) {
		Vector drawings = med.getDrawings();
		
		for(int i=0; i< drawings.size(); i++) {
			Drawing d = (Drawing)drawings.elementAt(i);
			if(d.contains(x, y))
				d.setFill(color); //fill drawing
		}
	}
}

Switching Between States

    지금까지 우리는 마우스 이벤트가 보내질 때 각 상태는 어떻게 행동하는지를 정의하였고 어떻게 StateManager가 상태들을 바꾸는지 논의할 필요가 있다; 우리는 선택된 버튼에 의해 지시되는 상태로 currentState 변수를 정하였다.

import java.awt.*;

public class StateManager {
	private State currentState;
	RectState rState;
	ArrowState aState;
	CircleState cState;
	FillState fState;
	
	public StateManager(Mediator med) {
		rState = new RectState(med);
		cState = new CircleState(med);
		aState = new ArrowState(med);
		fState = new FillState(med);
		currentState = aState;
	}
	
	public void setRect() {
		currentState = rState;
	}
	
	public void setCircle() {
		currentState = cState;
	}
	
	public void setFill() {
		currentState = fState;
	}
	
	public void setArrow() {
		currentState = aState;
	}
    StateManager에서 우리는 생성자에서 각 상태의 인스턴스를 생성하고  set 메소드가 호출될 때 상태 변수에 정확한 인스턴스를 저장한다. 요구에 따라 이 상태들을 생성하기 위해  Factory를 사용하는 것도 가능하다.

    StateManager의 나머지 코드는 간단하게 현재 state 객체가 어떤 것이건 간에 메소들을 호출한다. 이 부분이 결정적인 부분이다 -- 거기에는 어떤 조건적인 검사가 없다. 대신 정확한 상태는 이미 정해져 있고 그것의 메소들은 이미 호출될 준비가 되어 있다.

How the Mediator Interacts with the State Manager

우리는 Mediator의 버튼과 마우스 이벤트 관리로부터 state 관리를 분리하는 것이 명확하다는 것을 언급했다. Mediator는 결정적인 클래스이지만 현재 프로그램 상태가 변경되면 StateManager에게 알려준다. Mediator 의 시작 부분은 어떻게 이 상태 변경을 처리할 수 있는가를 설명한다:


public Mediator() {
	startRect = false;
	dSelected = false;
	drawings = new Vector();
	undoList = new Vector();
	stMgr = new StateManager(this);
}

//-------------------------------------------
public void startRectangle() {
	stMgr.setRect();
	arrowButton.setSelected(false);
	circButton.setSelected(false);
	fillButton.setSelected(false);
}

//---------------------------------------------
public void startCircle() {
	stMgr.setCircle();
	rectButton.setSelected(false);
	arrowButton.setSelected(false);
	fillButton.setSelected(false);
}
이러한 startXxx 메소들은 Command 객체로서 각 버튼의 Execute 메소드들로부터 호출되어 진다.

Consequences of the Observer Pattern

  1. State 패턴은 각 상태에 대한 개별적인 클래스에서 state-specific 행위로 제한하고 하나의 객체에서 상태를 위한 모든 행동을 넣는다.
     
  2. 프로그램의 코드를 통하여 산재되어 있는 조건문과 같은 거에 대한 필요성을 제거해 준다.
     
  3. 뚜렷한 트랜지션을 만든다.
     
  4. State 객체들은 인스턴스 변수가 없다면 공유되어 질 수 있다. 여기서는 Fill 객체만 인스턴스 변수를 가지고 있고 색은 다른 아규먼트로 만들 수 있다.
     
  5. 이 방법은 다량의 규모가 작은 클래스들을 생성하는 방식이지만 프로세스에서 프로그램을 단순화하고 명백하게 설명한다.

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

[펌] The Template Pattern  (0) 2011.08.13
[펌] The Strategy Pattern  (0) 2011.08.13
[펌] The Singleton Pattern  (0) 2011.08.13
[펌] The Proxy Pattern  (0) 2011.08.13
[펌] The Prototype Pattern  (0) 2011.08.13
안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,

The Singleton Pattern

Singleton 패턴은 Creational 패턴들과 같은 그룹에 속하지만, "non-creational" 패턴의 확장적인 면이 있다. 프로그래밍에서 클래스의 인스턴스를 하나만을 갖게 해야 할 경우가 있다. 예를 들어 우리의 시스템은 오직 하나의 윈도우 메니져나 프린트 스풀러를 가질 수 있다. 

유일하게 하나의 인스턴스를 갖는 클래스를 만드는 가장 간단한 방법은 static 변수를 클래스에 포함시키는 것이다. static 변수는 유일한 인스턴스의 하나이고, 인스턴스의 수는 문제가 되지 않는다.
static boolean instance_flag = false;

문제는 생성된 인스턴스가 성공적인지 아닌지를 어떻게 찾는가 인데 이것은  생성자가 반환을 하지 않기 때문이다. 한가지 방법은 생성의 성공여부를 체크하는 메소드를 호출하는 것이다. 그리고 메소드들은 static 변수로부터 유도된 값을 반환한다. 이 방법은 세련되지 못하고 오류들을 발생할 수 있는 경향이 있지만, .................................

좀더 나은 방법은 하나 이상 인스턴스가 생성될 때 예외(Exception)를 발생하는 클래스를 생성하는 것이다. 이런 경우에 우리 자신의 예외 클래스를 생성해 보자 : 

class SingletonException extends RuntimeException {

	//new exception type for singleton classes
	public SingletonException() {
		super();
	}
     //-----------------------------------------------
	public SingletonException(String s) {
		super(s);
	}
}

이 새로운 예외 타입은 특별하게 새로 작성된 내용없이 부모의 클래스를 호출할 것 뿐이다. 그러나  PrintSpooler의 인스턴스를 시도할 때 우리가 잡아야만 하는 예외의 타입을 컴파일러는 우리 자신이 이름을 지은 예외 타입으로 경고하는 편리함이 있다. 

Throwing the Exception

PrintSpooler 클래스의 골격을 작성해 보자; 프린팅 메소드들은 생략하고 단지 정확한 Singleton 패턴의 구현에만 초점을 둘 것이다. 
class PrintSpooler {

	//this is a prototype for a printer-spooler class
	//such that only one instance can ever exist
	static boolean instance_flag = false;	//true if 1 instance
	
	public PrintSpooler() throws SingletonException {
		if (instance_flag)
			throw new SingletonException("Only one spooler allowed");
		else 
			instance_flag = true;	//set flag for 1 instance
		
		System.out.println("spooler opened");
	}
	
	//----------------------------------------------
	
	public void finalize() {
		instance_flag = false;	//clear if destroyed
	}
}

Creating an Instance of the Class

지금까지 우리는 PrintSpooler 클래스에서 Singleton 패턴을 생성하였다. 이제 그 것을 어떻게 사용하는 지 알아보자. 예외를 발생시킬 지도 모르는 모든 메소드들에 대하여 try - catch 블럭안에 에워싸야한다는 것을 기억하자. 

public class SingleSpooler {

	public static void main(String[] args) {
		PrintSpooler pr1, pr2;
		
		//open on spooler--this should always work
		System.out.println("Open one spooler");
		try {
			pr1 = new PrintSpooler();
		}
		catch(SingletonException e) {
			System.out.println(e.getMessage());
		}
		
		//try to open another spooler -- should fail
		System.out.println("Open two spoolers");
		try {
			pr2 = new PrintSpooler();
		}
		catch(SingletonException e) {
			System.out.println(e.getMessage());
		}
	}
}

그리고 나서, 프로그램을 실행시키면 아래와 같은 결과를 얻을 수 있다.

            ##########0* 

Static Classes as Singleton Patterns

표준 자바 라이브러리에는 이미 Singleton 클래스의 종류가 있다:Math 클래스 . 이 클래스는 final로 선언되어 있고 모든 메소들이 static 으로 선언되어 있다. 이는 확장될 수 없음을 의미한다. Math 클래스의 목적은 sin이나 cos 처럼 일반적으로 사용되는 수학적인 함수들을 포장해 놓은 것이다. 

우리는 Singleton 클래스를 final 클래스로 하여 Singleton 패턴을 구현할 수 있다. 우리는 Math 클래스 처럼 어떤 인스턴스도 만들 수 없고, final 클래스에 존재하는 static 메소드들을 직접 호출해서만 사용할 수 있다. 
final class PrintSpooler {
	//a static class implementation of Singleton pattern
	static public void print(String s) {
		System.out.println(s);
	}
}

//==============================

public class StaticPrint {
   	public static void main(String argv[]) {
	      PrintSpooler.print("here it is");
	}
}
final 클래스 접근의 이점중의 하나는 try-catch 블럭을 쓸 필요가 없다는 거다. 이 이점은 만약 우리가 Singleton 상태를 중지하고자 한다면 예외 처리 스타일의 구조보다 더 쉽다는 것이다. 

Creating Singleton Using a Static Method

Design Patterns에 제안된 또 하한의 접근은 인스턴스들의 자취를 유지하고 유출하는 static 메소드를 사용하여 Singleton을 생성하는 것이다. 하나 이상의 인스턴스가 만들어 지는 것을 막기 위해 그 클래스의 static 메소드에서만 생성될 수 있는 private 의 생성자를 만든다.

class iSpooler {

	//this is a prototype for a printer-spooler class
	//such that only one instance can ever exist
	static boolean instance_flag = false; //true if 1 instance

	private iSpooler() {
	}

	static public iSpooler Instance() {
   		if (! instance_flag) {
			instance_flag = true;
			return new iSpooler();
		}
		else
			return null;      
	}
	//-------------------------------------------
	public void finalize() {
		instance_flag = false;
	}
}                                                        

이렇게 함으로써 얻는 주요 이점은 singleton이 이미 존재한다면 예외처리에 대해서는 신경 쓰지 않아도 된다는 것이다. 또, iSpooler 클래스의 인스턴스를 만드려 한다면 생성자가 private로 선언되어 있어 컴파일시 실패하게 될 것이다.

Other Consequences of the Singleton Pattern

  1. Singleton을 하위 클래스로 만드는 것은 어려울 수 있는데, 이것은 상위의 Singleton 클래스가 생성되지 않았을 때만 작동하기 때문이다.
  2. 우리는 적당하고 의미있는 곳에서의 작은 수의 인스턴스를 허용하는 Singleton으로 쉽게 바꿀 수 있다.

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

[펌] The Strategy Pattern  (0) 2011.08.13
[펌] The State Pattern  (0) 2011.08.13
[펌] The Proxy Pattern  (0) 2011.08.13
[펌] The Prototype Pattern  (0) 2011.08.13
[펌] The Observer Pattern  (0) 2011.08.13
안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,

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);
	}
}

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

        ##########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 DNS server, DNS service
Posted by 키르히아이스
,

The Prototype Pattern

    프로토타입 패턴은 매우 시간을 많이 소비하거나 좀 복잡한 클래스의 인스턴스를 생성할 때 사용된다. 그래서, 더 많은 인스턴스를 생성하는 것 보다는 인스턴스 원본의 사본을 만들어 적당하게 수정하는 것이 낫다. 

    프로토타입들을 그것들이 제공하는 처리과정의 타입에서만 다른 클래스들을 필요로 할 때마다 사용되어질 수 있다. 

Cloning in Java

        clone 메소드를 이용하여 자바의 어떤 객체이든지 간에 사본을 만들 수 있다. 

Jobj j1 = (Jobj)j0.clone();

    clone 메소드는 항상 Object 타입의 객체를 반환한다. 그래서 복사한 객체의 실제 타입으로 형 변환을 해야 한다. clone 메소드를 사용할 때는 3가지 중요한 제한사항이 있다. 
  1. clone 메소드는 protected 메소드이고 그 클래스를 포함하는 같은 클래스나 모듈내에서만 호출 되어질 수 있다.
  2. Cloneable 인터페이스를 구현하기 위해 선언한 객체에 대해서만 사본을 만들 수 있다.
  3. CloneNotSupported Exception을 발생하는 객체는 사본을 만들 수 없다.
public class SwimData implements Cloneable
	public Object clone() {
		try {
			return super.clone();
		}
		catch(Exception e) {
			System.out.println(e.getMessage());
			return null;
		}
	}
}

Using the Prototype

이제 수영선수들에 대한 정보를 데이터베이스에서 읽어 결과를 복제하는 프로그램을 작성해보자. 우리의 예에서는 간단히 파일에서 읽을 것이다.

    그 다음 이름, 클럽 이름, 성별과 기록(시간)을 갖는 Swimmer라는 클래스를 생성한다.

class Swimmer {
	String name;
	int age;
	String club;
	float time;
	boolean female;
	
	//-----------------
	
그리고, 파일에서 읽은 수영선수들을 하나의 벡터의 자료형으로 유지하는 SwimData 클래스를 생성한다.

public class SwimData implements Cloneable {
	protected Vector swimmers;
	public SwimData(String filename) {
		String s = "";
		swimmers = new Vector();
		InputFile f = new InputFile(filename);
		s= f.readLine();
		while(s != null) {
			swimmers.addElement(new Swimmer(s));
			s= f.readLine();
		}
		f.close();
	}	
	
	//--------------------------------
	
	public Object clone() {
		try {
			return super.clone();
		}
		catch(Exception e) {
			System.out.println(e.getMessage());
			return null;
		}
	}
	

Consequences of the Prototype Pattern

프로토타입 패턴을 사용함으로써, 필요할 때 복사하여 실행 중 클래스들을 추가하거나 제거할 수 있다.

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

[펌] The Singleton Pattern  (0) 2011.08.13
[펌] The Proxy Pattern  (0) 2011.08.13
[펌] The Observer Pattern  (0) 2011.08.13
[펌] The Memento Pattern  (0) 2011.08.13
[펌] The Mediator Pattern  (0) 2011.08.13
안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,