2005년 2월 28일 월요일

Behavioral Patterns

Behavioral Patterns

    Behavioral 패턴들은 객체들 사이의 통신과 관련된 가장 명확한 패턴이다. 이 단원에서는 다음과 같은 패턴들을 살펴볼 것이다.

The Observer Pattern (in the Learning the Java Language trail)

Observer 패턴은 클래스들이 서로 변경을 알아 챌 수 있도록 하는 방법을 정의한다.

The Mediator Pattern (in the Learning the Java Language trail)

Mediator 패턴은 클래스간에 서로 아는 것을 갖는 것으로부터 모든 클래스들을 유지하기 위하여  또 다른 클래스를 사용함으로써 간단하게 클래스 간의 통신을 어떻게 할 지를 정의한다.

The Chain of Responsibilty Pattern (in the Learning the Java Language trail)

Chain of Responsibility 는 클래스가 인식될 때까지 클래스들 사이의 요청을 전달하여 클래스들 사이의 디커플링을 훨씬 더 허용하는 것이다. 

The Template Pattern (in the Learning the Java Language trail)

Template 는 알고리즘의 추상적인 정의를 제공한다.

The Interpreter Pattern (in the Learning the Java Language trail)

Interpreters 는 프로그램에서 언어 요소들을 어떻게 포함할 것인가에 대한 정의를 제공한다. 

The Strategy Pattern (in the Learning the Java Language trail)

Strategy 는 하나의 클래스 내부에서 알고리즘을 캡슐화한다.  

The Visitor Pattern (in the Learning the Java Language trail)

Visitor 패턴은 클래스에 함수를 추가한다.

The State Pattern (in the Learning the Java Language trail)

State 패턴은 클래스의 인스턴스 변수들을 위한 메모리를 제공한다.

The Command Pattern (in the Learning the Java Language trail)

Command 패턴은 명령의 실행을 일으키는 인터페이스 환경으로부터 명령의 실행을 분리하기 위한 간단한 방법을 제공한다.

The Iterator Pattern (in the Learning the Java Language trail)

Iterator 패턴은 클래스에 있는 데이터의 목록을 통하여 우리는 이동하는 방법을 공식화한다.

Summary of Structural Patterns

Summary of Structural Patterns

  • Adapter 패턴은 어떤 클래스의 인터페이스를 다른 클래스의 인터페이스로 변경할 때 사용한다.
  • Bridge 패턴은 클라이언트 프로그램에서 나타내거나 사용하는 실제적인 종류의 클래스들을 변경을 허용하는 동안  일정한 인터페이스를  유지하려는 의도를 가지고 있다.
  • Composite 패턴은 객체들의 수집이나 그 자체가 조합되어 있는 객체들의 수집이다. 
  • Decorator 패턴은 클래스가 주어졌을 때 그것을 새로운 가능성을 추가하고, 기저 클래스에 변경되지 않은 메소드를 건내준다. 
  • Facade 패턴은 복잡한 상속구조의 객체들의 그룹에서 그러한 데이터를 접근할 수 있는 간단한 인터페이스를 제공한다.
  • Flyweight 패턴은 작고, 유사한 클래스 인스턴스의 급증을 외부의 클래스 데이터로 옮기고 메소들일 실행되는 동안 그 데이터들을 건내주어 제한하는 방법을 제공한다. 
  • Proxy 패턴은 인스턴스를 만드는데 비용이 많이 드는 좀더 복잡한 클래스에 대하여 간단한 place-holder 클래스를 제공한다. 

The Decorator Pattern

The Decorator Pattern

    데코레이터 패턴은 새로 상속 받아 클래스를 생성하는 것 없이 개별의 객체들의 행위를 수정할 수 있는 방법을 제공한다. 8개의 객체들을 가지는 프로그램이 있다고 해보자. 그러나 그 중 3개는 추가적인 속성이 필요하다. 이러한 객체들의 각각에 대하여 상속받아 클래스를 생성할 수도 있고, 많은 경우에 이것은 완벽하게 받아 들일 수 있는 해결책일 수 있다. 그러나, 이 세 객체의 각각이 다른 수정을 요구한다면, 이것은 세 개의 상속 받은 클래스를 생성하는 것을 의미한다. 게다가, 클래스들 중에 하나가 다른 두개 클래스의 특성을 가지고 있다면, 혼란스럽고 불필요한 클래스를 생성하게 된다. 

    예를 들어, 툴바에 있는 몇몇 버튼들 주위에 특별한 테두리를 그리려 한다고 가정해 보자. 만약 우리가 파생 받은  새로운 버튼 클래스를 생성했다면, 새로운 클래스의 모든 버튼들은 의도하지 않을 때도 항상 같은 새로운 테두리를 갖음을 의미한다. 

    대신, 버튼들을 장식하는 Decorator 클래스를 생성해 보자. 그리고 나서 Decorator 클래스로부터 특별한 Decorator들을 파생시킨다.  버튼을 장식하기 위해, Decorator는 시각적인 환경으로부터 파생된 그래픽 객체이고, paint 메소드를 받는다. 그러나 Decorator는 장식할 수 있는 객체를 포함하는 것이다. 그것은 몇몇의 그래픽 메소드가 호출되는 것을 방해할 수 있다. 

Decorating a CoolButton

최근의 Internet Explorer 나 Netscape Navigator 와 같은 윈도우즈 어프리케이션들은 마우스가 올라 갔을 때는 테두리가 나타나고 그렇지 않은 때는 테두리가 없는 버튼 들의 행을 가지고 있다. 몇몇 윈도우즈 프로그래머들은 그것을 CoolBar 또는 CoolButtons라 부른다. JFC에는 그와 비슷한 작동을 하는 버튼이 없지만, 우리는 decorating JButton으로 그러한 작동을 얻을 수 있다. 이러한 경우에, 우리는 버튼 테두리 위에 회색 선을 그리거나 지워서 장식을 한다.  
    어떻게 Decorator를 생성할 지를 고려해 보자. 디자인 패턴에서는 일반적인 시각적 컴포넌트 클래스로부터 파생받아 실제적인 버튼을 위한 모든 메시지가 decorator로부터 전달될 수 있게 한다. 자바에서는 우리가 재구현해야 하는 기본적인 JComponent에서 수백개의 메소드를 호출할 수 있으므로  완벽하게 실용적이다. 

    디자인 패턴은 Decorator 와 같은 클래스들은 추상클래스이어야 하고 실질적인 작업은 파생받은 클래스에서 하도록 제안한다. 자바에서 구현은 꼭 그렇게 할 필요가 없는데, 왜냐면 상위의 Decorator 클래스는 public 메소드를 가지고 있지 않기 때문이고 public 메소드를 가지지 않은 것은 JComponent 클래스의 메소드 자체이기 때문이다. 
public class Decorator extends JComponent {   public Decorator(JComponent c) {      setLayout(new BorderLayout());      add("Center", c);   }}
    이제 어떻게 CoolButton을 구한할 수 있는지 알아보자. 우리가 해야 할 필요가 있는 것은 상위 클래스로부터 일반적인 버튼을 그리는 것이고, 버튼 주변을 회색으로 그리고 지우는 것이다. 
//this class decorates a CoolButton so that//the borders are invisible when the mouse//is not over the buttonpublic class CoolDecorator extends Decorator {   boolean mouse_over;    //true when mose over button   JComponent thisComp;   public CoolDecorator(JComponent c){      super(c);      mouse_over = false;      thisComp = this;      //save this component      //catch mouse movements in inner class      c.addMouseListener(new MouseAdapter() { 	      public void mouseEntered(MouseEvent e) {	         mouse_over=true;     //set flag when mouse over	         thisComp.repaint();	      }	      public void mouseExited(MouseEvent e) {	         mouse_over=false;    //clear flag when mouse not over	         thisComp.repaint();	      }      });   }   //paint the button   public void paint(Graphics g) {      super.paint(g);      //first draw the parent button      if(! mouse_over) {         //if the mouse is not over the button         //erase the borders         Dimension size = super.getSize();         g.setColor(Color.lightGray);         g.drawRect(0, 0, size.width-1, size.height-1);         g.drawLine(size.width-2, 0, size.width-2, size.height-1);         g.drawLine(0, size.height-2, size.width-2, size.height-2);      }   }}

Using a Decorator

지금까지는 CoolDecorator 클래스를 작성해보았는데, 그것을 어떻게 사용할 것인가? 우리는 CoolDecorator의 인스턴스를 생석할 수 있고 장식하고자 하는 버튼으로 넘겨줄 수 있다.  CoolButton과 보통의 JButton을 가지는 프로그램을 생각해 보자. 우리는 아래처럼 레이아웃을 잡을 수 있다. 
super ("Deco Button");                                         JPanel jp = new JPanel();                                                                                                     getContentPane().add(jp);                                      jp.add(new JButton("Cbutton"));                                jp.add( new CoolDecorator(new JButton("Dbutton")));            jp.add(Quit = new JButton("Quit"));                            Quit.addActionListener(this);                                  
    프로그램은 아래와 같다. 마우스가 올라 가면 버튼의 테두리가 그려질 것이다.

               

Inheritance Order

    어떤 사람들은 JComponent 로부터 상속받은 decorator를 가지고  하나의 버튼을 장식하기 때문에  혼란스럽운 Decorator들의 상속순서를 찾는다. 아래의 그림은 상속 관계를 나타낸 것이다. 


Consequences of the Decorator Pattern

    Decorator 패턴은 상속을 사용하기보다는 하나의 클래스에 책임을 추가하여 보다 유연한 방법을 제공한다. 또한 복잡한 상속관계 없이 하나의 클래스를 정의할 수 있게 해준다. 디자인 패턴은 두 가지 단점을 지적하였는데, 하나는 Decorator와 그 안에 있는 컴포넌트가 동일하지 않다는 것이다. 그래서 객체 타입에 대한 검사를 할 수 없다. Decorator 패턴의 두 번째 결점은 프로그래머가 유지해야 할 코드들을 가지는 작지만 많은 객체들을 유도할 수 있다는 것이다. 이것은 골치거리가 될 수 있다. 

The Bridge Pattern

The Bridge Pattern

    브리지 패턴은 클래스의 구현으로부터 인터페이스를 분리하는데 사용되어진다. 브리지 패턴은 추상화 정도에 의한 계층으로 구분되어 있고 또 이를 구현하는데 있어 몇 개의 계층으로 나누는 경우에 유용한 패턴이다. 추상화 정도와 구현에 따라 완전히 구별되는 여러 클래스로 나누기 보다는 이를 동적으로 조합되는 몇 개의 상이한 클래스로 관리한다. 

    어떤 생산물의 목록을 하나의 화면에 나타내고자 한다 가정해 보자. 나타내기 위한 가장 간단한 방법은 "JList" 클래스를 사용하는 것이다. 그러나, 생산물의 일부분은 팔리게 되었다면, 우리는 판매와 관련하여 하나의 표안에 생산물을 나타내고자 할 지도 모른다. 

    우리는 앞에서 어댑터 패턴에 대하여 공부했는데, 어댑터에 기반의 클래스를 생각하게 될 지도 모른다. 간단한 예제프로그램은 잘 작동을 하겠지만, 접근에 몇몇 제한사항이 있다는 것을 알게 될 것이다.

    우리의 생산물의 데이터로부터 두 가지의 디스플레이가 필요하다고 해보자. 우리가 언급했던 생산물의 목록은 단지 customer view에서 나타나고, executive view에서는 선적된 양을 보여 줄 것이다.  생산품 리스트는 보통 JList 를 이용하여 나타내고, executive view는 JTable로 나타낼 것이다. 

           

    상위의 프로그래밍 단계에서는 단지 JList 와 JTable에서 파생된 테이블과 리스트의 인스턴스만을 생성하였다.
      pleft.add("North", new JLabel("Customer view"));      pleft.add("Center", new productList(prod));            //add in execute view as table      pright.add("North", new JLabel("Executive view"));      pright.add("Center", new productTable(prod));
또, 작성된 JawList 클래스로부터 직접 productList 클래스를 파생시켰다.
public class productList extends JawtList {  public productList(Vector products) {         super(products.size());    //for compatibility      for (int i = 0; i < products.size(); i++) {         //take each strig apart and keep only         //the product names, discarding the quntities         String s = (String)products.elementAt(i);         int index = s.indexOf("--");  //separate qty from name         if(index > 0)            add(s.substring(0, index));         else            add(s);      }  }}

Building a Bridge

이제 데이터를 나타내는 리스트 방법에서 몇 가지 변경사항이 필요하다 가정해보자. 예를 들어, 생산물의 목록을 알파벳 순으로 정렬하고자 할 수도 있다. 이렇게 하기 위해서는 상속된 클래스들의 수정을 필요하게 된다. 우리가 나타내야 할 것이 두개 이상이 된다면 더더욱 끔찍한 작업이 될 것이다. 변경된 내용을 나타내기 위해 새로운 클래스를 파생시키는 것보다는 brige를 만들어 작업하는 것이 더 나을 것이다. 



우리가 가시적인 컴포넌트를 반환하고자 한다면, 스크롤이 있는 패널의 일종으로 만들 수 있다.
public class listBridge extends JScrollPane
브리지 클래스를 설계할 때, 여러 클래스의 인스턴스를 브리지가 어떻게 결정할 것인지를 결정해야 한다. 나타날 데이터의 값이 성질에 기인하여 결정할 수도 있거나, 간단한 상수에 의해서 결정될 수도 있다. 여기서는 브리지 클래스 내에 두개의 상수를 정의하는 방식을 사용하였다. 
static public final int TABLE = 1, LIST = 2;
우리는 메인 클래스의 대부분은 유지하였으며, 새로운 listBridge의 생성자만을 약간 수정하였다.
pleft.add("North", new JLabel("Customer view"));pleft.add("Center", new listBridge(prod, listBridge.LIST));//add in execute view as tablepright.add("North", new JLabel("Execute view"));pright.add("Center", new listBridge(prod, listBridge.TABLE));
listBridge 클래스를 위한 생성자는,
public listBridge(Vector v, int table_type) {	Vector sort = sortVector(v);	//sort the Vector		if(table_type == LIST)		getViewport().add(makeList(sort));	//make list		if(table_type == TABLE)		getViewport().add(makeTable(sort));	//make table}
브리지 클래스에서 중요한 차이점은 JTable 과 JList클래스를 수정없이 직접 사용할 수 있다는 것이고 그렇게 때문에 리스트나 테이블을 위한 데이터를 생성하는 데이터 모델에서 어떤 인터페이스 컴퓨팅을 시도할 수 있다는 것이다.
private JList makeList(Vector v) {	return new JList(new BridgeListData(v));}private JTable makeTable(Vector v) {	return new JTable(new prodModel(v));}
정렬된 결과는 다음 그림과 같다.



Consequences of the Bridge Pattern

  1. 브리지 패턴은 나타내거나 사용하는 클래스의 실제적인 종류의 변경을 허용하는 반면에 클라이언트 프로그램 상수에 인터페이스를 유지하는 것을 의도한다. 이것은 복잡한 사용자 인터페이스의 모듈들을 다시 컴파일하는 것을 방지하고 브리지와 실제로 보여지는 말단의 클래스만 재컴파일하는 것을 요구한다.
  2. 구현되는 클래스와 브리지 클래스를 분할하여 확장할 수 있고, 상호간의 많은 상호작용을 제거해 준다.
  3. 훨씬 쉽게 크라이언트 프로그램에서 상세한 구현을 숨길 수 있다.

The Flyweight Pattern

The Flyweight Pattern

    데이터를 표현하기 위한 작은 클래스의 인스턴스들을 많이 생성해야 할 경우가 있다.
종종, 만약 몇개의  파라미터에 대한 것만 제외하고 기본적으로 같은 같은 인스턴스들이다라는 것을 인식할 수 있다면 인스턴스를 만들 필요가 있는 서로 다른 클래스들의 수를 크게 줄일 수 있다. 만약 그러한 변수들을 클래스 인스턴스의 외부로 옮길 수 있고 메소드가 호출하는 부분에서 그것들을 건내 줄수 있다면 나뉘어진 인스턴스의 수는 크게 줄일 수 있다. 

    Flyweight 디자인 패턴은 그러한 클래스들을 조절하는 거에 대해서 방법을 제시한다. 인스턴스가 유일하도록 인스턴스의 고유한 데이터를 참조하고, 아규먼트로 전달되는 고유하지 않는 데이터를 참조하게 한다. Flyweight는 각각의 문자들이나 스크린사의 아이콘과 같은 작고, 자잘 자잘한 클래스들에 대해  어울린다.  예를 들어, 사람이나 데이터에 대해 각각 표현을 하는 폴더 윈도우에서 화면상의 아이콘의 시리즈를 추출한다고 하면 ,사람의 이름이나 화면상의 아이콘의 위치 를 기억하는 것에 대해 각각의 클래스 인스턴스를 만드는 것은 의미가 없다. 전형적으로 그러한 아이콘들은 몇몇 유사한 이미지들중의 하나이고,추출되는 위치는 어떤 경우에서든지 윈도우의 크기에 따라 동적으로 계산되어 진다. 

    디자인 패턴에서의 다른 예는 폰트에서 각각의 문자는 문자 클래스의 하나의 인스턴스로 표현되어지지만, 글자들이 스크린 상에서 그려지는 위치는 문자의 각각의 외양에 대한 것 보다는 각 문자의 하나의 인스턴스만 필요하게 하는 외부 데이터로서 유지된다.       

Discussion

    Flyweight들은 클래스의 인스턴스를 공유할 수 있다. 그것은 Singleton 클래스처럼 보일 수도 있지만 사실 적은 수의 인스턴스들이 있을 수 있다. 할당된 인스턴스의 수는 클래스 인스턴스가 필요할 때 결정되어야 하며, 이것은 Flyweight 클래스로 이루어 진다. 이 팩토리 클래스는 특별한 인스턴스가 생성되었는지 아닌지를 추적해야 하기 때문에 보통 싱글턴이다. 특수한 인스턴스가 이미 생성되어 있으면 새로운 인스턴스나 레퍼런스를 반환한다.    
    프로그램의 일부분이 Flyweight를 사용할 후보인지를 결정하기 위하여 클래스로부터 몇몇 데이터를 제거하고 그것을 외부의 변수로 만들어도 가능한가를 고려해 본다. 프로그램을 유지하는데 필요한 다른 클래스 인스턴스의 수를 크게 줄이는게 가능하도록 한다면 Flyweight 가 도울 수 있는 경우이다.  

Example Code

    우리가 하나의 조직에서 각 사람에 대해서 작은 폴더 아이콘 아래 이름을 가지는 작은 폴더 아이콘을 그리고 싶다고 해보자. 만약 이것이 큰 조직이라면 그러한 아이콘의 수는 커지게 되겠지만, 그것들은 실제적으로 작은 그래픽 이미지들이다. 우리가 두개의 아이콘을 가지고 있다고 하더라도 하는 선택되지 않은 거에 대한 것이고 다른 하나는 선택것에 대한 아이콘이다. 각 사람에 대한 아이콘 객체와 그 것들 자체의 좌표, 이름과 선택된 상태를 갖는 시스템은 자원의 낭비이다. 

    대신, 우리는 선택되거나 선택되지 않은 것을 나타내는 drawing 클래스를 반환하는 FolderFactory를 생성하겠지만, 이미 생성된 각각의 인스턴스에 대하여 추가적인  인스턴스 생성은 하지 않을 것이다. 
	class FolderFactory {	Folder unSelected, Selected;	public FolderFactory() {		Color brown = new Color(0x5f5f1c);		Selected =  new Folder(brown);		unSelected = new Folder(Color.yellow);	}	//-------------------------------  	public Folder getFolder(boolean isSelected) {		if (isSelected) 			return Selected;		else			return unSelected;	}}
    더 이상의 인스턴스들이 존재할 수 있는 경우들에 대해서, factory는 이미 생성되었던 인스턴스에 대한 표를 유지할 수 있고 오직 테이블에서 이미 존재하지 않을 때에만 새로운 인스턴스를 생성한다. 

    그러나, Flyweight를 사용하는 것에 대한 유일한 것은 우리가 폴더 아이콘을 그릴 때 좌표와 이름을 넘겨주는 것이다. 이러한 좌표들은 폴더 객체를 공유하도록 하는 외부의 데이터이고 이 경우에 오직 두 개의 인스턴스만을 생성한다. 완성된 폴더 클래스는 아래의 코드 처럼 간단하게 폴더 인스턴스를 하나의 배경색과 다른  정한 폴더를 그릴 수 있는 public Draw 메소드를 가지고 생성할 수 있다. 
	class Folder extends JPanel {	private Color color;	final int W = 50, H = 30;	public Folder(Color c) {	   color = c;	}	//-------------------------------  	public void Draw(Graphics g, int tx, int ty, String name) {		g.setColor(Color.black);            //outline		g.drawRect(tx, ty, W, H);		g.drawString(name, tx, ty + H+15);  //title				g.setColor(color);                  //fill rectangle 		g.fillRect(tx+1, ty+1, W-1, H-1);				g.setColor(Color.lightGray);        //bend line   		g.drawLine(tx+1, ty+H-5, tx+W-1, ty+H-5);				g.setColor(Color.black);            //shadow lines		g.drawLine(tx, ty+H+1, tx+W-1, ty+H+1);		g.drawLine(tx+W+1, ty, tx+W+1, ty+H);				g.setColor(Color.white);            //highlight lines		g.drawLine(tx+1, ty+1, tx+W-1, ty+1);		g.drawLine(tx+1, ty+1, tx+1, ty+H-1);  	}}
이와 같은 Flyweight 클래스를 사용하기 위해서, 메인 프로그램은 각 폴더의 위치를 계산해야 하고, 그리고 나서 좌표를 폴더 인스턴스에 건내 주어야 한다. 이것은 실제로 보다 일반적인 방법인데, 왜냐면 윈도우의 크기에 의존하는 서로 다른 레이아웃을 필요로 하기 때문이다. 대신, 우리는 paint 루틴 동안 동적으로 계산한다. 

    여기서 우리는 우리가 외부에서 폴더들의 벡터나 배열을 생성할 수 있고 각 폴더를 그리기 위해 배열을 통하여 간단히 읽어 들일 수 있다는 것을 주목해야 한다. 그러한 배열은 다른 인스턴스들의 시리즈 처럼 낭비가 아니다. 왜냐하면 그것은 실제로는 두 개의 폴더 인스턴스 중의 하나를 참조하는 배열이기 때문이다. 그러나, ㅇ뤼는 하나의 폴더가 선택된것으로 나타내고자 하고, 폴더의 상태를 동적으로 변경시키고자 하기 때문에, 우리는 바로 각 시간에 정확하게 인스턴스를 줄 수 있는 FolderFactory를 사용한다. 
	public void paint(Graphics g) {	Folder f;	String name;		int j = 0;      //count number in row	int row = Top;  //start in upper left	int x = Left;		//go through all the names and folders	for (int i = 0; i< names.size(); i++) {		name = (String)names.elementAt(i);		if(name.equals(selectedName))			f = fact.getFolder(true);		else			f = fact.getFolder(false);					//have that folder draw itself at this spot		f.Draw(g, x, row, name);				x = x + HSpace;          //change to next posn		j++;				if (j >= HCount) {        //reset for next row					j = 0;         			row += VSpace;			x = Left;		}	}}

Selecting A Folder

    우리가  선택된 상태거나 선택되지 않은 상태와 관련된 두개의 폴더 인스턴스를 갖기 때문에, 우리는 그 것들 위로 마우스를 움직여서 폴더가 선택되었는지를 알 수 있기를 원한다. 위의 paint 루틴에서 우리는 간단히 선택된 폴더의 이름을 기억하고 factory가 선택된 폴더로 반환하기를 요청한다. 폴더들이 개별적인 인스턴스들을 갖지 않기 때문에 우리는 각 폴더 인스턴스 내에서 마우스의 움직임을 감지할 수 없다. 사실, 하나의 폴더내에서 감지 할 수 있다 하더라도, 우리는 선택되지 않는 폴더의 인스턴스들에게 알려줄 방법을 가지고 있어야만 한다. 

    대신, 우리는 윈도우 단계에서 마우스의 움직임을 체크하고 만ㅇ약 마우스가 사각형 내에서 발견된다면 우리는 선택된 이름과 대응되는 이름을 만들어 낼 수 있다. 이것이 우리가 다시 그리고 필요한 곳에서 선택된 폴더 인스턴스를 생성할 때 체크할 수 있도록 허용한다.  
public void mouseMoved(MouseEvent e) {	int j = 0;      //count number in row	int row = Top;  //start in upper left	int x = Left;		//go through all the names and folders	for (int i = 0; i< names.size(); i++) {		//see if this folder contains the mouse		Rectangle r = new Rectangle(x,row,W,H);		if (r.contains(e.getX(), e.getY())) {			 selectedName=(String)names.elementAt(i);			 repaint();		}		x = x + HSpace;          //change to next posn		j++;		if (j >= HCount) {        //reset for next row			j = 0;         			row += VSpace;			x = Left;		}	}}
10개의 이름이 있는 폴더를 나타내는 프로그램은 아래와 같다.

   

Flyweight Uses in Java

Flyweights는 자바에서 어프리케이션 단계에서는 자주 사용되지 않는다. 그것들은 자바보다 저수준의 단계에서 사용되는 시스템의 자원을 관리하는 기술이다. 그러나, 필요할 때 사용할 수 있기 위해서 이 기술이 존재하는 것을 알아두는 것은 유용한다. 

    Flyweights 가 사용되는 곳은 테이블과 리스트를 위해 사용되는 cell renderer 코드이다. 보통 셀 렌더러는 단지 JLabel이지만 labels의 두 세가지 타입이 있을 수 있거나 다른 색이나 폰트에 대해 렌더링을 할 수 있다. 그러나 테이블이나 리스트에서 셀보다는 렌더러가 더 적다. 

    자바언어에 있는 몇몇 객체들은 Flyweight로서 포장되어 구현될 수 있다. 예를 들어 동일한 문자들을 갖는 문자열의 인스턴스가 두개가 있다면 같은 저장 위치를 참조하게 할 수 있다. 마찬가지로 같은 값을 갖는 Interger 나 Float 객체는 Flyweight로 구현될 수 있다. Flyweights 의 부재를 증명하기 위해 다음 코드를 실행시켜 보자. 
Integer five = new Integer(5);          Integer myfive = new Integer(5);        System.out.println(five==myfive);                                        //String fred = new String("fred");     //String fred1 = new String("fred");                                            String fred ="fred";                    String fred1 ="fred";                                                           System.out.println(fred==fred1);        
    두 가지 모두 "false" 를 출력할 것이다. 그러나 "==" 연산자를 이용하여 Flyweight의 두 개의 같은 인스턴스들의 문제를 처리할 때 쉽게 결정할 수 있다는 것은 유용하다. 그것은 사실 같은가에 대한 비교가 아니라 레퍼런스(메모리 주소)를 비교하는 것이다. 

The Facade Pattern

The Facade Pattern

    종종 프로그램이 전개되고 개발됨에 따라, 프로그램들은 복잡해진다. 사실, 디자인 패턴을 이용하는 거에 대한 흥분은 이러한 패턴들이 때때로 프로그램의 흐름을 이해하는 것을 어렵게 하는 많은 클래스들을 생성한다는 것이다. 게다가, 그것들은 복잡한 시스템일 수도 있고, 복잡한 인터페이스를 가지고 있을 수도 있다. 

    Facade 패턴은 이러한 하위 시스템에 대한 간단한 인터페이스를 제공하여 복잡한 것을 간단히 만드는 것이다. 이 간단성이 놓여있는 클래스의 유연성을 줄이는 경우가 있지만, 보통 대부분의 약아빠진 사용자들을 제외하고는 모두에게 필요한 함수를 제공한다. 

    다행스럽게도, 우리는 Facade가 유용하게 사용될 수 있는 예에 대하여 제공되는 복잡한 시스템을 작성할 필요가 없다. 자바는 JDBC라 불리는 인터페이스를 사용하여 데이터베이스에 연결되는 클래스들의 집합을 제공한다. 프로그램 개발자가 제공하는 JDBC 연결 클래스를 이용하여 어떤 데이터베이스 든  연결할 수 있다. 몇몇 데이터베이스드은 JDBC를 이용하여 직접적인 연결을 할 수 있고 몇몇은 JDBC-ODBC bridge 클래스를 이용하여 ODBC 드라이버에 연결을 허용한다. 

    이러한 java.sql 패키지에 있는 데이터베이스 관련 클래스들은 아래의 그림처럼 휘감는 방식으로 상호작용을 하는 저수준의 클래스들의 집합의 예를 제공한다. 

       

    데이터베이스를 연결하기 위해서, Connection 클래스의 인스턴스를 사용한다. 그리고 나서, 데이터베이스 테이블들의 이름과 필드들의 이름을 찾기 위해, Connection 으로부터 DatabaseMeta 클래스의 인스턴스를 얻는 것이 필요하다. 다음, 질의를 하기 위해 SQL 질의어를 만들고 Statement 클래스를 생성하는 Connecion 을 이용한다. 문장을 실행함으로서, ResultSet 클래스르 얻을 수 있고, ResultSet 클래스에서 필드들의 이름을 찾기 위해 ResultsetMetadata의 클래스의 인스턴스를 얻는 것이 필요하다. 
그러므로, 이러한 클래스 모두를 조작하는 것은 꾀나 어려울 수 있다. 왜냐면 대부분 그런 클래스들의 호출되는 메소드들은 예외를 발생시킬 수 있고, 코딩이 복잡해 질 수 있기 때문이다. 

           

        그러나, 데이터베이스 클래스와 resultSet 클래스의 구성을 Facade로 디자인함으로써, 우리는 훨씬 더 유용한 시스템을 만들 수 있다.     

Building the Facade Classes

    어떻게 데이터베이스를 연결할 것인지 고려해보자. 우리는 우선 데이터베이스 드라이버를 읽어들여야 한다.   
try {	Class.forName(driver);} //load the Bridge drivercatch(Exception e) {	System.out.println(e.getMessage());}
    그리고 나서 데이터베이스를 연결하기 위한  Connection 클래스를 이용한다. 우리는 또한 데이터베이스에 대하여 좀더 많은 것을 알아 내기 위해 데이터베이스의 메타데이터를 얻을 수 있다: 
try {	con = DriverManager.getConnection(url);	dma = con.getMetaData(); //get the meta data}catch(Exception e) {	System.out.println(e.getMessage());}
만약 우리가 데이터베이스에서 테이블들의 이름 목록을 얻고자 한다면, 우리는 데이터베이스 메타 데이터 클래스상의 ResultSet 객체로 반환되는 getTables 메소드를 호출할 필요가 있다. 마지막으로, 이름들의 목록을 얻기 위해 그 객체들을 통하여 이터레이터를 해야 한다. 
Vector tname = new Vector();try {	results = new ResultSet(dma.getTables(catalog, null, "%", type));}catch(Exception e) {	System.out.println(e.getMessage());}while(results.hasMoreElements())	tname.addElement(results.getColumnValue("TABLE_NAME"));
이것은 관리하기가 꾀나 관리하기가 복잡해졌고, 아직은 어떤 질의어도 사용하지 않았다. 

    우리가 만들 수 있는 간략화 가정은 이러한 데이터베이스 클래스 메소드들이 발생시키는 예외를 복잡하게 핸들링 할 필요가 없게 하는 하는 것이다. 대부분은 메소드들이 데이터베이 연결에서 실패를 하지 않는다면 오류 없이 작동할 것이다. 그러므로, 우리는 오류들을 드문 드문 일어나는 오류들을 감지하고 더 이상의 행동을 취하지 않도록 클래스들의 메소드를 포장할 수 있을 것이다. 

    이것이 Connection, ResultSet, Statement 와 Metadata 클래스들의 의미있는 메소드들을 포함하는 두개의 클래스로 작성할 수 있을 것이다. 이 두 클래스는 Database 클래스이고 :
class Database {	public Database(String driver)() //constructor	public void Open(String url, String cat);	public String[] getTableNames();	public String[] getColumnNames(String table);	public String getColoumnValue(String table, String columnName);	public String getNextValue(String columnName);	public resultSet Execute(String sql);}
    이고 resultSet 클래스는 :
class resultSet {	public resultSet(ResultSet rset)	//	public String[] getMetaData();	public boolean hasMoreElements();	public String[] nextElement();	public String getColumnValue(String columnName);	public String getColumnValue(int i);}
    이 간단한 클래스들은 데이터베이스를 열고, 데이터베이스에 있는 테이블의 이름이나, 열의 이름과 내용, 간단한 쿼리에 의해  표시될 수 있도록 해준다. 

       

    그리고 텍스트 입력창에 SQL 쿼리를 입력하고 Run Query 버튼을 누르면 그에 따른 결과를 보여준다.

       

Consequences of the Facade

    Facade 패턴은 복잡한 하부 시스템의 컴포넌트로부터 클라이언트들을 포장하고 일반적인 사용자를 위한 보다 간단한 프로그래밍 인터페이스를 제공한다. 그러나 그것은 숙달된 사용자가 좀더 심도있고, 필요에 따라 클래스를 좀더 복잡하게 하는 것을 막을 수 없다. 

    게다가 Facade 는 클라이언트 코드에서 수정의 요구 없이 근원이 되는 하부 시스템에서의 변경을 할 수 있게 해주고, 복잡한 의존들을 줄여준다. 

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가 원본 객체를 복사할 수 있고, 새로운 인스턴스로 변경되는 것을 만들 수 있다. 이것은 객체들이 인스턴스가 된 후 항상 변경하지 않을 때 시간과 공간을 크게 줄일 수 있게 한다. 

The Composite Pattern

The Composite Pattern

종종 프로그래머들은 독립적인 객체나 객체들의 수집으로 표현될 수 있는 객체를 갖는 컴포넌트로 이루어진 시스템을 개발한다. 컴포지트 패턴은 위의 두 가지 경우를  조정하기 위하여 계획되어진다. 컴포지트 패턴은 부분-전체의 상속을 만들거나 트리로 데이터를 표현하는 걸 만들려 할 때 사용되어 질 수 있다. 요약해서, 하나의 컴포지트는 객체들의 수집이다. 트리 목록에서, 어떤 객체들은 추가적인 가지들을 가지는 노드일 수도 있고 어떤것들은 잎들일 수도 있다.

    하나의 조합에서 모든 객체들에 접근할 수 있는 인터페이스 분리가 문제이고, 노드들과 잎 사이를 구분하는 것이 문제이다.  노드들은 자식을 가질 수 있고, 자식들은 노드를 가질 수 있는 반면, 잎들은 자식을 가질 수 없고, 구현할 때는  잎들은 노드를 가지지 않도록 해야한다. 

    몇몇 사람들은 노드와 잎을 구분하는 인터페이스를 만들것을 제안하였고, 여기서 잎은 메소드들은 가질 수 있다.

public String getName();public String getValue();
    그리고 노드는 추가적인 메소들을 가질 수 있다 :
public Enumeration elements();public Node getChild(String nodeName);public void add(Object obj);public void remove(Object obj);
    이 다음 엘리먼트들이 언제 컴포지트를 생성해야하는가에 대한 프로그래밍 문제를 남긴다.그러나, 디자인 패턴은 각 엘리먼트가 컴포지트이건 원래의 엘리먼트이건 간에 같은 인터페이스를 갖도록 할 것을 제안한다. 이것은 목표를 이루기가 좀더 쉽지만, getChild() 연산이 객체가 실제적으로 잎일 때 어떻게 완성될 수 있는지에 대한 질문을 남기게 된다. 
    자바는 이것을 아주 쉽게 만들었는데, 왜냐면, 모든 노드나 잎이 자식이 어디에 저장되어 있는지에 대한 벡터의 내용의Enumeration을 반환할 수 있기 때문이다. 만약 자식이 없으면, hasMoreElements() 메소드가 바로 false를 반환한다. 그러므로, 각 엘리먼트에서 Enumeration을 얻을 수 있다면 우리는 hasMoreElements() 메소드를 체크함으로써 어떤 자식이 있는가를 결정할 수 있다.

An Implementation of Composite

작은 회사를 생각해 보자. 경영을 하는 한 사람을 가지고 시작할 수 있다. 그 사람은 물론 CEO이다. 그리고 그 사람은  마케팅과 제조를 담당하는 두사람을 고용하였다. 곧, 각각의 사람은 추가적으로 광고, 선적 기타 등등을 도울 수 있는 사람을 고용했다. 그리고 그들은 회사의 첫 번째 부회장이 되었다. 회사가 계속해서 성장함에 따라, 우리가 아래 그림에서 볼 수 있는 것처럼 구조화 될 것이다:



    이제, 그 회사가 성공해서, 그 회사의 각각의 사원은 봉급을 받고, 그 회사의 고용비용을 물어 볼 수 있다. 우리는 모든 사원에 대한 봉급으로서 그 비용을 정한다. 여기에 컴포지트에 대한 이상적인 예가 있다.
  • 각 개인의 고용비용은 각 개인의 봉급이다.
  • 한 부서의 고용비용은 그 부서의 책임자와 그들의 부하직원의  봉급의 합이다.
    우리는 고용인이 부하직원이 있든 없든 간에 정확한 전체의 봉급을 계산하는 하나의 인터페이스를 만들고자 한다.  
public float getSalaries();
여기에서, 우리는 표준의 같은 인터페이스를 갖는 모든 컴포지트들의 생각이 아마 원시적이라는 것을 깨달았을 것이다. 우리는 실제로 개발하고 있는 모든 클래스의 종류와 관련된 public 메소드들을 선호할 것이다. getValue()와 같은 일반적인 메소드를 갖는 것보다는 우리는 getSalaries()를 사용할 것이다. 

The Employee Class

우리의 Employee 클래스는 각 고용인의 이름과 봉급을 저장할 것이고, 필요에 따라 그들을 부를 수 있게 할 것이다. 
public class Employee {	String name;	float salary;	Vector subordinates;		//-----------------------		public Employee(String _name, float _salary) {		name = _name;		salary = _salary;		subordinates = new Vector();	}		//-------------------------		public float getSalary() {		return salary;	}		//------------------------		public String getName() {		return name;	}
    클래스가 인스턴스가 될 때 subordinates라 불리는 벡터가 생성된다는 것을 주목해야 한다. 그리고 나서, 만약 employee가 하위를 갖는 다면 우리는 자동으로 add 메소드를 이용하여 벡터에 추가할 수 있고  remove 메소드를 이용하여 벡터에서 제거할 수 있을 것이다.  
public void add(Employee e) {	subordinates.addElement(e);}//-----------------------------public void remove(Employee e) {	subordinates.removeElement(e);}
    만약 우리가 주어진 상위의 employee들의 리스트를 얻고자 한다면 subordinates 벡터로부터 직접적으로 그것들의 Enumeration을 얻을 수 있다. 
public Enumeration elements() {	return subordinates.elements();}
그 클래스의 중요한 부분은 어떻게 employee 와 그의 subordinates에 대하여 봉급의 총합을 반환하는 가이다. 
public float getSalaries() {	float sum=salary;	//this one's salary	//add in subordinates salaries	for(int i=0; i < subordinates.size(); i++) {		sum += ((Employee)subordinates.elementAt(i)).getSalaries();	}		return sum;}
이 메소드는 현재 Employee의 봉급을 가지고 출발하고 나서 각 subordinate에 대하여 getSalaries() 메소드를 호출한다는 것을 주목해야 한다. 

Building the Employee Tree

우리는 CEO Employee를 생성하여 시작하고 그의 suborinates를 추가한다.
boss = new Employee("CEO", 200000);boss.add(marketVP = new Employee("Marketing VP", 100000));boss.add(prodVP = new Employee("Production VP", 100000));marketVP.add(salesMgr = new Employee("Sales Mgr", 50000));marketVP.add(advMgr = new Employee("Advt Mgr", 50000));for (int i=0; i<5; i++)    salesMgr .add(new Employee("Sales "+new Integer(i).toString(), 30000.0F +(float)(Math.random()-0.5)*10000));advMgr.add(new Employee("Secy", 20000));prodVP.add(prodMgr = new Employee("Prod Mgr", 40000));prodVP.add(shipMgr = new Employee("Ship Mgr", 35000));for (int i = 0; i < 4; i++)  prodMgr.add( new Employee("Manuf "+new Integer(i).toString(), 25000.0F +(float)(Math.random()-0.5)*5000));for (int i = 0; i < 3; i++)  shipMgr.add( new Employee("ShipClrk "+new Integer(i).toString(), 20000.0F +(float)(Math.random()-0.5)*5000));
    일단 컴포지트 구소작 생성되면, 우리는 상위 노드에서 부터 시작하고  접근할 수 있는 각 노드의 잎이 있을 때까지 재귀적으로 addNode()라 불리는 메소드를 호출하여 JTree를 시각적으로 보여줄 수 있다.
private void addNodes(DefaultMutableTreeNode pnode, Employee emp) {	DefaultMutableTreeNode node;                                	Enumeration e = emp.elements();                                    	while(e.hasMoreElements()) {		Employee newEmp = (Employee)e.nextElement();               		node = new DefaultMutableTreeNode(newEmp.getName());       		pnode.add(node);                                           		addNodes(node, newEmp);                                    	}                                                          }      
아래 그림은 최종적인 프로그램이다:

       

    이 구현에서, 비용(전체 봉급 합)은 아래의 버튼에 보여지게 된다. 이 간단한 계산은  메소드가 employee의 모든 suborinates를 얻기 위해서 getChild()라 불리는 재귀적으로 부른다.
public void valueChanged(TreeSelectionEvent evt) {	TreePath path = evt.getPath();	String selectedTerm = path.getLastPathComponent().toString();		Employee emp = boss.getChild(selectedTerm);	if(emp != null)		cost.setText(new Float(emp.getSalaries()).toString());}

Restrictions on Employee Classes

어떤 employee나 job positions 은 suborinates를 갖지 않도록 설계되어질 수 있다. 집적된 workers 나 salesmen은 승진을 할수도 있는데, 잎의 위치는 suborinates가 추가될 수 없다. 이런 경우에 반영구적인 잎 위치를 정할 수 있도록 Employee 클래스를 디자인 하고자 할 수 있다. 이것을 하기 위한 하나의 방법은 subordinates가 추가되는 것을 허용하기 전에 검사되는 변수를 정하는 것이다. 만약 직위가 잎 위치라면 그 메소드는 false를 반환하거나 예외를 발생시킬 것이다. 
public void setLeaf(boolean b) {	isLeaf = b;    //if true, do not allow children}//--------------------------------------public boolean add(Employee e) {   	if (! isLeaf)       		subordinates.addElement(e);      	return isLeaf;    //false if unsuccessful}   

Consequences of the Composite Pattern

컴포지트 패턴은 간단한 객체나 복잡한 조합의 객체들의 상속관계를 같은 클라이언트 프로그램에서 나타내기 위하여 정의한다. 이 단순성 때문에 클라이언트는 좀더 간단해질 수 있는데, 노드와 잎들이 같은 방식으로 조절되기 때문이다. 

    컴포지트 패턴은 또한 컬렉션에 새로운 종류의 컴포넌트를 그것들이 같은 프로그래밍 인터페이스를 제공하는 동안 쉽게 추가할 수 있도록 한다. 반면에 이것은 지나치게 일반적이게 하는 단점을 가지고 있다. 

Other Implementation Issues

    Implementing the list in the parent. 만약 컴포지트에서 노드는 몇 안되고 거대한 양의 노드를 가지고 있다면, 각 잎에서의 빈 벡터 객체를 유지하는 것은 공간 문제와 관련이 있다. 하나의 대안적인 접근은 단지 getName()와 getValue()메소드 만을 갖는 Member 타입의 모든 객체들을  선언하는 것이다.그리고 나서  Member로부터 add, remove 와 elements 메소드를 구현한 Node 클래스를 상속 받는다. 비어 있는 벡터 enumerator들을 반환하는 대신 재귀적인 루프에서 체크를 할 수 있다. 
 
if(emp instanceof Node) {	Enumeration e = emp.elements();	while(e.hasMoreElements()) {		Employee newEmp = (Employee)e.nextElement();			//--------	}
대부분의 경우에 이렇게 하여 공간을 절약한다는 주장은 명확하지가 않다. 

    Ordering components. 몇몇 프로그램에서, 컴포넌트의 순서는 중요할 수 있다. 예를 들어, 원래의 벡터를 알파벳순으로 정렬할 수 있고, 정렬된 새로운 벡터에 대한 Enumerator를 반환한다. 

The Adapter Pattern

The Adapter Pattern

    어댑터 패턴은 어떤 클래스의 인터페이스 프로그래밍을 다른 클래스로 변환할 때 사용되어진다. 우리는 어댑터를 하나의 프로그램에서 함께 작업하는 클래스간에 서로 관련성이 없게 하고자 할 때 사용한다. 어댑터의 개념은 그러므로 간단하다; 우리는 요구되는 인터페이스를 갖는 클래스를 작성하고 다른 인터페이스를 갖는 클래스와 통신할 수 있게 한다. 

    어댑터를 구현하는 방법에는 상속에 의한 방법과 객체 조합에 의한 방법이 있다. 첫번째 경우에서, 우리는  상속 받는 새로운 클래스를 만들고 요구되는 인터페이스에 매치되는 상속받은 새로운 클래스를 만들기 위해 필요로 하는 메소드를 추가한다. 다른 방법은 새로운 클래스 내부에 원본의 클래스를 포함하는 방법이고 새로운 클래스 내부에서 호출되는 변환하기 위한 메소드를 생성한다. 

Adapters in Java

        자바언어에서는 많은 어댑터들이 이미 구성되어 있다. 이 경우에, 자바 어댑터는 이벤트 인터페이스가 불필요하게 복잡하지 않도록 해준다. 이러한 자바 어댑터 들 중에서 빈번하게 사용되는 예는 WindowAdapter 클래스이다.      
	public class MainFrame extends Frame implements WindowListener {	public MainFrame() {		addWindowListener(this);	//frame listens						//for window events	}		public void windowClosing(WindowEvent e) {		System.exit(0);	//exit on System exit box clicked	}		public void windowClosed(WindowEvent e){ }	public void windowOpened(WindowEvent e){ }	public void windowIconified(WindowEvent e){ }	public void windowDeiconified(WindowEvent e){ }	public void windowActivated(WindowEvent e){ }	public void windowDeactivated(WindowEvent e){ }}
위에서 있는 코드는 읽기도 힘들고 작성하기도 번거로운 코드이다. 이 문제를 WindowAdapter 클래스는 간단하게 해결해 준다. 
	//illustrates using the WindowAdapter classpublic class Closer extends Frame {		public Closer() {		addWindowListener(new WinAp());				//----------------------------	}}class WinAp extends WidowAdapter {	public void windowClosing(WindowEvent e) {		System.exit(0);	}	);}

Structural Patterns

Structural Patterns

    Structural 패턴들은 어떻게 클래스들과 객체들이 좀 더 큰 구조에서 결합될 수 있는가를 설명한다. 클래스 패턴과 객체 패턴 사이의 차이점은 클래스 패턴은 어떻게 인스턴스가 프로그램 인터페이스들에 좀더 유용되게 사용되어 질 수 있는가를 설명하는 것이다. 반면 객체 패턴들은 어떻게 객체들이 객체 조합이나 다른 객체를 포함하는 객체들을 조합할 수 있는가를 설명하는 것이다. 

    예를 들어 우리는  다음과 같은 패턴들을 알아 볼 것이다.

The Adapter Pattern (in the Learning the Java Language trail)

Adapter 패턴은 더 쉽게 프로그래밍 할 수 있도록 인터페이스에 어울리는 하나의 클래스를 만들어 사용할 수 있다.

The Composite Pattern (in the Learning the Java Language trail)

Composite 패턴은 간단하거나 여러개의 객체로 이루어진 객체들의 조합에 관한 것이다.

The Proxy Pattern (in the Learning the Java Language trail)

Proxy 패턴은 좀더 복잡한 객체가 후에 호출 될 수 있도록 하는 간단한 객체이다. 

The Flyweight Pattern (in the Learning the Java Language trail)

동일한 정보를 가지고 있는 객체의 인스턴스들이 상호 교환된다면 Flyweight 패턴은 하나의 객체로 정보를 공유해 여러 개의 객체 인스턴스로 인한 비용 소모를 피할 수 있다.

The Facade Pattern (in the Learning the Java Language trail)

Facade 패턴은 완전한 하위 시스템을 나타내기 위한 한 개의 클래스를 만드는 데 사용되어진다. 

The Bridge Pattern (in the Learning the Java Language trail)

Bridge 패턴은 추상의 계층관계와 상응하는 추상의 구현이 존재할 때 유용하다. 추상 클래스와 구현 클래스를 여러 개의 구분된 클래스로 나눠 구현하지 않고, 추상 클래스와 구현 클래스를 별개의 클래스로 구현해 이들이 동적으로 조합되도록 한다.  

The Decorator Pattern (in the Learning the Java Language trail)

Decorator 패턴은 객체들에게 동적으로  해야 할 일들을 추가 시키는데 사용될 수 있다.

The Prototype Pattern

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

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

The Builder Pattern

The Builder Pattern

    우리는 이미 생성 메소드의 인자로 넘겨지는 데이터에 의존하는 여러개의 서로 다른 하위 클래스 중의 하나를 반환하는 Factory 패턴을 보았었다. 그러나 단지 계산 알고리즘 뿐만 아니라 나타낼 필요가 있는 데이터에 의존하는 서로 다른 사용자 인터페이스를 가정해 보자. 전형적인 예는 이메일 주소록이 될 것이다. 아마 주소록에는 사람들과 사람들의 그룹 둘 다 가지고 있을 것이고, 사람이름, 회사, 이메일 주소, 전화번호를 가지고 있는 사람창을 변경시키기 위해 주소록을 디스플래이하기를 기대하게 될 것이다.

    반면에 주소 페이지에서 그룹을 표시하고자 한다면, 그룹의 이름을 보고자 할 것이다. 한 사람을 클릭하면 그룹과 다른 것들을 얻을 수 있다. 모든 이메일 주소는 아래 그림처럼 사람과 그룹을 파생시키는 상위 클래스 주소를 갖는 다고 가정하자:

           

    우리가 누르는 주소 객체의 타입에 따라, 객체들의 다른 속성을 나타내기를 원할 것이다. 이것은 팩토리 패턴보다는 약간 더 증가한 것인데, 왜냐하면 보여줄 객체에 의존하는 객체들을 반환하는 것이 아니라 전체적으로 다른 사용자 인터페이스가 보여줄 객체들의 서로 다른 조합을 만드는 것이기 때문이다. 빌더 패턴은 객체들을 조합하는 것이다. 

An Investment Tracker

    사용자 인터페이스를 세울 클래스를 어디에서 유용하게 사용될 수 있는지를 고려해 보자. 투자의 수행을 추적하는 프로그램을 작성하고자 한다고 하자. 우리는 주식, 채권, 상호 기금 등을 가질 수 있고, 각 범주의 보유 목록을 나타내고자 하고 그래서 하나 또는 이상의 투자를 선택하고 그것들의 상대적인 성취도를 표시하고자 한다. 우리가 어떤 주어진 시간에 얼마나 많은 투자의 종류가 있는지 미리 예측할 수는 없다 하더라도 쉽게 대규모의 기금이나 소규모의 기금이 사용되는지를 나타내고자 한다. 각각의 경우에, 우리는 하나 또는 그 이상의 기름을 선택할 수 있는 다중 선택 디스플레이를 정렬하고자 한다. 만약 대규모의 기금이 있다면, 우리는 다중 선택이 가능한 리스트 박스를 사용할 것이고, 3개 또는 몇 안되는 기금이 있으면 체크박스를 사용할 것이다. 우리는 표시 될 항목의 수에 따라 인터페이스를 생성하는 빌더 클래스를 원하고, 아직까지 결과를 반환하기 위한 같은 메소드들을 가지고 있다. 

    우리의 디스플레이들은 아래에서 보여진다. 첫번째 디스플레이는 대규모의 주식을 포함하고 두번째는 소규모의 채권을 포함하고 있다. 

             

           

    이제, 변수들을 나타낼 인터페이스를 어떻게 생성할 수 있는지 고려해 보자. 우리는 구현 할 필요가 있는 메소드를 정의한 multiChoice라는 추상 클래스로부터 시작해 보자.
abstract class multiChoice {	//This is the abstract base class	//that the listbox and checkbox choice panels	//are defived from	Vector choices;	//array of labels		//---------------------------------------		public multiChoice(Vector choiceList) {		choices = choiceList;	//save the list	}		//to be implemented in derived classes	abstract public JPanel getUI();	//return a Panel of components	abstract public String[] getSelected();	//get list of items	abstract public void clearAll();	//clear selections}
getUI 메소드는 다중 선택을 나타내는 패널을 반환한다. 여기서 우리가 사용하는 두 개의 디스플레이는 체크박스 패널 또는 리스트박스 패널이다. -- 이 추상 클래스로부터 상속 받은 

class listboxChoice extends multiChoice 
            또는
class checkBoxChoice extends multiChoice

그리고 나서, 이 두개의 상속 받은 클래스를 반환할 팩토리 클래스를 만든다:
class choiceFactory {	MultiChoice ui;	//This class returns a Panel containing	//a set of choices displayed by one of 	//several UI methods	public MultiChoice getChoiceUI(Vector choices) {		if(choices.size()<=3)			//return a panel of checkboxes			ui = new checkBoxChoice(choices);		else			//return a multi-select list box panel			ui = new listBoxChoice(choices);				return ui;	}}

Consequences of the Builder Pattern

  1. 빌더는 세워지는 것의 내부적인 표현을 변경할 수 있게 한다. 또, 어떻게 생성된 것이 조립되었는지를 감추어 준다.
  2. 각각의 특수한 빌더는 프로그램의 나머지 부분과는 독립적이다. 이것이 모듈화를 향상시키고 상대적으로 간단하게 다른 빌더들을 추가적으로 만들어 준다 
        빌더 패턴은 일련의 메소드와 객체들로 이루어진 클래스를 반환한다는 점에서는 추상화 패턴과 유사하다. 두 패턴 사이의 중요한 차이는 추상화 팩토리 패턴이 관련된 클래스의 하나의 족을 반환하는데 반해 빌더는 표현해야 하는 데이터에 의존하는 복잡한 객체를 단계적으로 생성한다는데 있다. 

The Singleton Pattern

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());		}	}}
그리고 나서, 프로그램을 실행시키면 아래와 같은 결과를 얻을 수 있다.

             

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으로 쉽게 바꿀 수 있다.

The Abstract Factory Pattern

The Abstract Factory Pattern

추상화 팩토리 패턴은 팩토리 패턴보다 더 추상화한 단계이다. 이 패턴은 연관된 객체의 여러 클래스들 중의 하나를 반환하고자 할 때 사용할 수 있다. 즉, 추상화 팩토리는 여러 팩토리들 중의 하나를 반환하는 팩토리 객체이다.

    추상화 팩토리의 고전적인 응용중의 하나는 컴퓨터시스템이 다중의 "룩앤필(look-and-feel)"을 지원하는 경우에서의 사용이다. 여기서 팩토리는 사용하는 시스템이 windows이면 windows를 반환하는 객체이다.

    자바에서는 룩앤필을 지원하는데 그 사용예를 잠깐 살펴보자.
 String laf = UIManager.getSystemLookAndFeelClassName();try {	UIManager.setLookAndFeel(laf);}catch (UnsupportedLookAndFeelException exc) {	System.err.println("UnsupportedL&F: " + laf);}catch (Exception exc) {	System.out.println("Error loading " + laf);}

A GardenMaker Factory

    응용단계에서 사용하고자 하는 추상화 팩토리의 간단한 예를 고려해 보자. 

  정원의 배치에 관련된 프로그램을 작성한다고 하자.
정원은 일년생 식물의 정원일 수 있고, 야채를 가꾸는 정원일 수 있고, 다년생의 식물들이 사는 정원일 수 도 있다.
그러나, 우리가 계획하는 정원의 종류와는 상관없이 다음과 같은 사항들에 대해 고려하게 될 것이다.

1. 가장자리에는 어떤 식물을 심는 것이 좋을 것인가?
2. 중앙에는 어떤 식물들이 좋을 것인가?
3. 응달진 부분에는 어떤 식물들이 좋을 것인가?

    ... 이외에도 많은 요구 사항들이 있겠지만, 우리의 예에서는 생략할 것이다. 

Garden 클래스는 이러한 요구들에 대한 기본 클래스이다.
 public abstract class Garden {	public abstract Plant getCenter();	public abstract Plant getBorder();	public abstract Plant getShade();}
현실 세계에서는 보다 정교하게 식물의 정보를 이용하여 정원의 형태를 다루겠지만, 우리의 예에서는 간단히 식물의 종류 중 하나를 반환할 것이다. 예를 들어 Vegertable garden은 다음과 같이 작성할 수 있다.
 public class VegieGarden extends Garden {	public Plant getShade() {		return new Plant("Broccoli");	}	public Plant getCenter() {		return new Plant("Corn");	}	public Plant getBorder() {		return new Plant("Peas");	}}
이제 우리는 일련의 Garden 객체들을 가지고 있으며, 각각의 객체들은 여러개의 Plant 객체중 하나를 반환하게 된다. 이제 우리는 인자로 문자열이 주어졌을 때 Gadend 객체중 하나를 반환하는 추상화 팩토리를 생성할 수 있다.
 class GardenMaker {//Abstract Factory which returns one of three gardens	private Garden gd;		public Garden getGarden(String gtype) {		gd = new VegieGarden();	//default 		if(gtype.equals("Perennial"))			gd=new PerennialGarden();		if(gtype.equals("Annual"))			gd=new AnnualGarden();				return gd;	}}
이 간단한 팩토리 시스템은 아래의 그림처럼 다소 복잡한 사용자 인터페이스를 이용하여 작동되어질 수 있다.

           

How the User Interface Works

     이 간단한 인터페이스는 두개의 부분으로 구성되어 있다. 좌측은 Garden 타입을 결정하는 라디오버튼으로 구성되어 있고, 우측은 식물의 카테고리를 결정할 수 있도록 버튼으로 구성되어 있다. Garden 타입 중 하나를 선택하였을 때, Garden 팩토리를 작동 시킨다. 이 것은 라디오버튼의 캡션에 의하여 Garden의 타입을 반환한다.
 public void itemStateChanged(ItemEvent e) {	JRadioButton rd = (JRadioButton)e.getSource();		//get a garden type based on label of radio button	garden = new GardenMaker().getGarden(rd.getLabel());		//Clear names of plants in display	shadePlant="";	centerPlant="";	borderPlant="";		gardenPlot.repaint();	//display empty garden}
그리고 나서 사용자가 식물 타입 버튼 중의 하나를 누르면, 식물의 타입은 반환되고, 식물의 이름이 나타난다.
 public void actionPerformed(ActionEvent e) {	Object obj = e.getSource();	if(obj==centerBTN)		setCenter();	if(obj==borderBTN)		setBord();	if(obj==shadeBTN)		setShade();}//----------------------------------------------------------private void setCenter() {	if(garden!=null)		centerPlant = garden.getCenter().getName();	gardenPlot.repaint();}private void setBord() {	if(garden!=null)		borderPlant = garden.getBorder().getName();	gardenPlot.repaint();}private void setShade() {	if(garden!=null)		shadePlant = garden.getShade().getName();	gardenPlot.repaint();}	
식물의 이름들은 GardenPanel에서 표시되며, 각 이름들은 그려진다.
 class GardenPanel extends JPanel {                            	public GardenPanel(){                                 		super();			              		setBackground(Color.white);                   		setBorder(LineBorder.createBlackLineBorder());	}                                                     	                                                      	public void paintComponent(Graphics g) {              		super.paintComponent(g);                      		                                              		//draw tree shadow                            		g.setColor(Color.lightGray);                  		g.fillArc(0,0,80,80,0,360);                   		                                              		//draw plants names                           		g.setColor(Color.black);                      		g.drawString(centerPlant, 100, 100);          		g.drawString(borderPlant, 75, 180);           		g.drawString(shadePlant, 10, 40);             	}                                                     }                                                               

Consequences of Abstract Factory

추상화 팩토리의 주요 목적 중의 하나는 생성된 구체적인 클래스들을 고립시키는 것이다. 이러한 클래스들의 실제적인 이름은 팩토리에 숨겨져 있고 클라이언트 단계에서 전혀 알려질 필요가 없다. 

    클래스들의 고립으로 이렇게 생성한 클래스 족 들을 자유롭게 바꿀 수 있다. 게다가, 구체적인 클래스 중의 하나를 생성하였기 때문에 이 시스템은 다른 종류의 클래스 족들로부터 우연한 사용을 유지하게 한다. 그러나 그것은 몇몇의 새로운 클래스 족들을 추가해야 하는 수고를 하여야 한다. 왜냐하면, 그러한 새로운 클래스 족들이 반환될 수 있는 상태를 새롭고 모호하지 않게 정의해야 하기 때문이다.

    반면에 생성된 추상화 팩토리의 모든 클래스들은 같은 상위 클래스를 가지고 있고, 다른 클래스들이 가지고 있는 메소드와는 다른 메소드를 추가하는 것을 방해하지 않는다.

The Factory Pattern

The Factory Pattern

객체 지향 프로그램에서 계속해서 볼 수 있는 패턴 중의 하나는 Factory 패턴 또는 클래스이다. Factory 패턴은 제공된 데이터에 의존하는 여러 가능한 클래스 중의 하나를 반환하는 것이다. 일반적으로 반환되는 모든 클래스는 공통적인 부모 클래스와 공통적인 메소들을 가지지만, 그것들은  각각은 다른 일을 하고, 다른 종류의 데이터를 위해 최적화 되어진다.

How a Factory Works

아래의 Factory 다이어 그램은 Factory 패턴의 이해를 돕기 위한 것이다.



그림에서 x는 상위 클래스이고 xy와 xz는 x로 부터 파생되었다. Factory는 입력된 인자에 의존하여 하위 클래스를 반환을 결정하는 클래스이다. 오른쪽에서 어떤 abc라는 값이 주어질 때의 getClass 메소드를 정의하였고, 이 메소드는 클래스 x의 인스턴스를 반환한다. 모두 같은 메소드를 가지고 있기 때문에 반환되는 getClass가 어떤 값을 반환하는가는 문제가 되지 않지만, 구현은 다르다. 어떻게 반환할 것인가를 결정하는 것은 전반적으로 Factroy에 의해서 이다. 

Sample Code

    Factory 클래스를 사용할 수 있는 간단한 경우를 고려해 보자.
우리가 어떤 가입 양식을 가지고 있고, 가입자가 그의 이름을 "이름 성" 또는 "성, 이름" 모두 가능하게 하고자 한다고 하자. 우리는 이름과 성 사이의 컴마(,)가 있는지 없는지를 고려하여 항상 이름의 순서를  결정할 수 있도록 좀더 가정을 단순화 시킬 것이다. 
class Namer {	// a simple class to take a string apart into two names		protected String last; 	//store last name here	protected String first;	//store first name here		public String getFirst() {		return first;	//return first name	}	public String getLast() {		return last;	//return last name	}	}
상위 클래스에는 두 개의 메소드를 제외하고는 실제적으로 아무일 도 하지 않는다. 우리는 first last 에 성과 이름을 분리하여 저장할 것이다. 

The Two Derived Classes

우리는 간단하게 생성자를 이용하여 이름을 두개의 부분으로 나누는 클래스를 파생시킬 수 있다. FirstFirst 클래스에서는 공백문자 이전의 모든 것들은 이름(last name)이라 가정한다.
class FirstFirst extends Namer { 		//split first last	public FirstFirst(String s) {		int i = s.lastIndexOf(" "); 	//find sep space		if( i>0) {			//left is first name 			first = s.substring(0,i).trim();			//right is last name			last = s.substring(i+1).trim();		}		else {			first = ""; 	// put all in last name			last = s;	// if no space		}	}}
그리고, LastFirst 클래스에서는 컴마(,)를 구분자로 하여 컴마 이전의 것은 이름(last)에 이후는 성(fist)에 저장할 것이다. 만약 컴마가 존재하지 않는다면 이름에 저장할 것이다.
class LastFirst extends Namer {	//split last, first	public LastFirst(String s) {		int i = s.indexOf(",");	//find comma		if (i>0) {			//left is last name 			last = s.substring(0,i).trim();			//right is first name			first = s.substring(i+1).trim();		}		else {			last = s; 	//put all in last name			first = "";	//if no comma		}	}}

Building the Factory

Factory 클래스는 아주 간단하다. 우리는 컴마의 존재 유무를 검사한 후 상속 받은 두 클래스중 하나의 인스턴스를 반환할 것 이다.
class NameFactory {//returns all instance of LastFirst or FirstFirst//depending on whether a comma is found	public Namer getNamer(String entry) {		int i = entry.indexOf(","); //comma determines name order		if (i>0)			return new LastFirst(entry); 	//return one class		else			return new FirstFirst(entry);	//or the other	}}
Using the Factory
어떻게 Factory를 사용하는지 알아 보자.
간단하게 성과 이름을 입력할 수 있는 입력창과 이름과 성을 분리하도록 명령을 내리는 버튼, 그에 따라 각각 분리하여 나타낼 수 있는 두 개의 결과창을 사용자 인터페이스로 구현해 보자. 아래의 그림은 구현은 이러한 일련의 작업을 구현해 놓은 애플릿이다.

           

이름을 입력하고 Compute 버튼을 누르면 이름과 성이 분리되어 각각의 결과를 얻을 수 있을 수 있을 것이다.
이 프로그램을 작성하기 위해 우리는 생성자에 Factory 클래스를 생성하여야 한다.

 NameFactory nfactory = new NameFactory();

그리고 나서 버튼 이벤트가 발생하였을 때 이름과 성을 분리할 수 있는 getNamer메소드를 호출 할 compteName이라는 메소드를 구현해야 한다. 
	private void computeName () {		//send the text to the factory and get a class back		namer = nfactory.getNamer(entryField.getText());				//compute the first and last names		//using the returned class		txFirstName.setText(namer.getFirst());		txLastName.setText(namer.getLast());	}

When to Use a Factory Pattern

다음과 같은 상황에서 Factory 패턴을 고려할 수 있다.
  • 객체들에 대한 클래스의 종류를 예상 할 수 없을 때
  • 어떤 객체들이 Factory Pattern을 생성하는지를 특정 짓기 위하여 클래스의 하위 클래스를 사용할 때
  • 생성된 클래스로터 얻어진 정보 제한하고자 할 때
Factory 패턴에 대한 여러가지 변형이 있다.
  1. 기본 클래스는 추상(abstract)이고 그 패턴은 완전하게 작동하는 클래스를 반환하여야 한다
  2. 기본 클래스는 디폴트 메소드들을 포함하고 오직 하위 클래스들이 .....

Creational Patterns

Creational Patterns

모든 Creational Patterns은 객체의 인스턴스를 생성하는 최상의 방법과 관련이 있다. 이것은 작성된 프로그램이 생성되고 배치된 객체들과 의존적이지 않아야 하기 때문에 중요하다. 자바에서는 가장 간단한 방법으로 new 연산자를 이용하여 객체들의 인스턴스를 생성하는 방법이다. 

                                Fred = new Fred() ; //instance of Fred class

그러나 이 방법은 프로그램 안에서 생성된 객체가 의존적이어서 결국 코딩이 어렵게 된다. 많은 경우에, 생성된 객체의 정확한 본질은 프로그램의 요구에 의하여 변경되어 질 수 있고, "createor"라는 특수한 클래스로의 추상화 과정은  프로그램을 보다 유연하고 일반적으로 만들 수 있게 한다.

The Factory Method (in the Learning the Java Language trail)

Factory 패턴은 제공되는 데이터에 의존하는 추상 기저 클래스의 가능한 하위 클래스들 중의 하나를 반환하는 간단한 의사 결정 클래스를 제공한다.

The Abstract Factory Method (in the Learning the Java Language trail)

Abstract Factory 패턴은 생성할 인터페이스를 제공하고, 관련된 객체들의 여러 군 중에서 하나를 반환한다.

The Singleton Pattern (in the Learning the Java Language trail)

Singleton 패턴은 오직 하나의 인스턴스만을 갖는 클래스이다. 그 것은 생성된 인스턴스에 접근하는 하나의 포괄적인 점을 제공한다.

The Builder Pattern (in the Learning the Java Language trail)

Builder 패턴은 단지 객체에 대한 형태와 내용만 지정함으로써, 복잡한 객체를 구성 할 수 있다. 즉, 각각의 객체 구성에 대한 모든 정보를 자세히 알고 있지 않아도 쉽게 객체를 구성 할 수 있다. 

The Prototype Pattern (in the Learning the Java Language trail)

Prototype 패턴은 어떤 객체의 생성 방식에 대한 자세한 정보를 모르더라도 그 객체가 원하는 다른 객체를 생성할 수 있도록 도와준다. 우선, 생성하려는 객체에 대한 프로토타입 객체를 미리 제공한 다음, 프로타입 객체의 복사본을 생성함으로써

The History of Design Patterns

The History of Design Patterns

소프트웨어에 대한 디자인 패턴의 아이디어는 건축 분야에서 나왔다. 1977년과 1979년에 건축가인 크리스토퍼 알렉산더(Christopher Alexander)는 “A Pattern Language:Towns, Buildings, Construction”라는 제목의 책과 “The Timeless Way of Building”이라는 제목의 책 두 권을 발표했다.  이 두 권의 책이 담고 있는 기본 아이디어는 건축물의 설계에 빈번하게 발생하는 동일 설계 내용이 있으며 따라서, 이런 것들을 하나의 패턴으로 보고 다른 건축물 설계에 재사용하는 것이 여러 가지 면에서 이득을 가져 다 준다는 것이다.  두 권의 책이 담고 있는 이런 기본 아이디어는 건축 영역을 벗어난 소프트웨어와  같은 다른 영역에서도 적용할 수 있었다. 

1987년 워드 커닝험(Ward Cunningham)과 켄트 벡(Kent Beck)은 알렉산더의 아이디어를 사용해서 사용자 인터페이스(User interface)에 대한 다섯 가지의 패턴을 만들었다. 그리고 이 내용은 “Using Pattern Languages for Object-Oriented Programs”라는 제목으로 정리되어 객체 지향에 관한 세계적인 컨퍼런스(conference)인 OOPSLA-87(Object-Oriented Programming, Systems, Languages & Applications .. 87)에 논문으로 발표되어 디자인 패턴에 대해서 학계에 공식적으로 알리는 계기가 되었다. 

1990년대 초에는 에릭 감마(Erich Gamma), 리차드 헬름(Richard Helm), 존 블리자이드(John Vlissides), 랄프 존슨(Ralph Johnson)이 90년대 가장 영향을 주었던 컴퓨터 책의 한 가지인 “Design Patterns: Elements of Reusable Object-Oriented Software”이란 책 제작을 시작 했다. 이 책은 1994년에 발표되어 디자인 패턴에 대한 아이디어를 널리 알리는 계기를 만들었으며, 이 책은 책의 제목이 긴 이유로 인해서 'GoF(Gang of Four) book'라는 별칭으로 불리고 있다. 

Defining Desing Patterns

  • 디자인 패턴은 개개의 클래스, 인스턴스 , 컴포넌트들의 상위 단계인 추상 개념을 확인하고 특정 짓는다.(Gamma, et al., 1993)
  • 디자인 패턴은 소프트웨어 개발의 범위에서 어떤 일을 어떻게 완수할 수 있는 가에 대한 규칙들로 이루어 진다.(Pree, 1994)
  • 디자인 패턴은 반복되는 구조의 디자인 주제의 재사용성에 좀더 초점을 둔다.(Coplien & Schmidt, 1995)

Definition: 자주 발생하는 문제들에 대한 "재사용 가능한 해결책"이다.

Some Background on Design Patterns

Some Background on Design Patterns

1995년 Richard Helm, Ralph Johnson, John Vlissides 는 그들의 저서에서 '객체지향 소프트웨어를 설계하는 일은 어려운 일이며, 재사용이 가능한 소프트웨어를 설계하는 일은 그 보다 한층 더 어려운 일'이라 했다. 디자인 패턴은 전문가들이 시행착오를 거쳐 만들어낸 경험의 산물이라 할 수 있다. 앞으로 소개 될 디자인 패턴들은 결국 재사용 가능한 객체들을 어떻게 설계한 것인가에 대한 경험적인 해답들이라 할 수 있을 것이다. 디자인 패턴들을 살펴 보기 전 객체지향 프로그램의 개념을 살펴 볼 것이며, 효율적인 객체지향 프로그램을 하기 위한 디자인 패턴의 정의를 내려 볼 것이다.

Object-Oriented Programming Concepts(in the Learning the Java Language trail)

객체는 변수들과 메소들로 이루어진 소프트웨어 번들이다. 소프트웨어 객체들은 우리의 일상에서 발견할 수 있는 실세계의 객체들을 모델링하는데 사용되어 진다. 

Defining Design Patterns(in the Learning the Java Language trail)

여러 사람들이 말하는 디자인 패턴에 대한 정의를 종합해 보면 디자인 패턴이란 한 마디로 

                            "소프트웨어 엔지니어의 경험"

이라 정의 할 수 있다.

The Mediator Pattern

The Mediator Pattern

    어떤 프로그램이 여러 개의  클래스로 만들어져 있을 때 로직과 계산은 이러한 클래스로부터 논리적으로 나뉘어 진다. 그러나 이러한 고립적인 클래스들이 증가함에 따라 이러한 클래스들의 통신 문제가 보다 복잡해졌다. 다른 클래스의 메소드들에 대하여 아는 것이 필요한 클래스가 더 많아지고 클래스들의 구조는 더 얽혀 복잡해 진다. 이것이 프로그램을 읽는 것과 유지를 어렵게 한다. 게다가 프로그램을 변경하는 것이 어려운데 왜냐면 어떤 변화가 여러 개의 다른 클래스들에서 코드에 영향을 줄 지도 모르기 때문이다. Mediator 패턴은 이러한 클래스들 사이의 느슨한 커플링을 진행하여 이러한 문제를 해결할 수 있는 방법을 소개한다. Mediator는 다른 클래스들의 메소드들에 대한 정보를 설명한 오직 하나의 클래스의 이용하여 이 문제를 해결할 수 있다. 클래스들은 변경되었을 때 mediator에게 정보를 준고 Mediator는 정보를 필요로 하는 다른 클래스들에게 정보를 전달해 준다.

An Example System

    여러 개의 버튼과 두 개의 리스트 박스와 입력할 수 있는 텍스트 필드를 갖는 프로그램을 생각해 보자:

       

    프로그램이 시작되었을 때는 Copy 와 Clear 버튼은 비 활성 상태이다.
  1. 좌측의 리스트 박스에서 이름들 중의 하나를 선택했을 때, 편집을 위한 텍스트 필드에 복사가 되고 Copy 버튼은 활성화 된다.
     
  2. Copy 버튼을 눌렀을 때, 그 텍스트는 우측의 리스트 박스에 추가되고 Clear 버튼이 활성화 된다.

        
     
  3. Clear 버튼을 눌렀다면 우측의 리스트 박스와 텍스트 필드는 지워지고 리스트 박스는 선택할 수 없고 두 개의 버튼은 다시 비 활성 상태가 된다.
    이와 같은 사용자 인터페이스는 공통적으로 사람이나 생산물의 목록의 선택에서 사용되어진다. 게다가 이렇게 만든 것보다 삽입, 삭제  와 취소와 같은 기능이 추가되어 더 복잡해 질 수 있다.

Interactions between Controls

시각적인 컨트롤들 사이에 상호작용은 이러한 간단한 예 조차 꾀 복잡하다. 각각의 시각적인 객체는 두 개나 더 이상의 객체들에 관해서 알 필요가 있어 아래 그림처럼 관계들이 얽혀 있을 수 있다.

   

    Mediator 패턴은 이 시스템에서 다른 클래스들을 인식할 수 있는 오직 하나의 클래스 두어 이 시스템을 단순화한다. Mediator 와 통신 하는 각각의 컨트롤들을 Colleague 라 부른다. 각각의 Colleague 는 사용자 이벤트를 받았을 때 Mediator 에게 통지하고 Mediator 는 이벤트가 통지 될 수 있는 다른 클래스들을 결정한다. 아래 그림은 상호 작용 구조를 단순화한 것이다.



    Mediator의 장점은 명확하다 -- 그것은 다른 클래스들에 대해 아는 오직 하나의 클래스를 갖고 그래서 다른 클래스들 중의 하나가 바뀌거나 다른 인터페이스 컨트롤 클래스가 추가된다면 그 클래스는 변경할 필요가 있다.

Sample Code

이 프로그램을 자세하게 고려하고 각각의 컨트롤이 어떻게 구축할 지를 결정해 보자. Mediator 클래스를 사용하는 프로그램 작성에서 주요 차이점은 각각의 클래스들은 Mediator의 존재를 알 필요가 있다. Mediator의 인스턴스를 만들어 시작하고 각 클래스의 생성자에 Mediator의 인스턴스를 전달한다. 
Mediator med = new Mediator();kidList = new KidList(med);tx = new KTextField(med);Move = new MoveButton(this, med);Clear = new ClearButton(thism med);med.init();
    우리는 각 컨트롤에 대해 새로운 클래스들을 만들었기 때문에 각 클래스 내에서 mediator 연산자를 조정할 수 있다.

    두 개의 버튼은 Command 패턴을 사용했고 초기화 되는 동안 Mediator에 등록하였다. CopyButton에 대한 코드는 아래와 같다 :
public class MoveButton extends JButton implements Command {	Mediator med;            //copy of the Mediator		public MoveButton(ActionListener fr, Mediator md) {		super("Copy");         //create the button		addActionListener(fr); //add its listener		med = md;              //copy in the Mediator instance		med.registerMove(this); //register with the Mediator   	}		public void Execute() {		//execute the copy		med.Move();	}}
Clear 버튼은 거의 비슷하다.
   
    아이의 이름 목록은 최근에 예에서 사용한 것에 기본을 두고 있지만 리스트의 데이터 로딩과 Mediator에 등록을 하기 위해 확장을 하였다. 추가적으로 우리는 ListSelectionListener를 구현하였고 어떤 리스트 항목을 누르건 Mediator에 정보를 줄 수 있도록 하였다.
public class KidList extends JawtList implements ListSelectionListener {	KidData kdata;	Mediator med;		public KidList(Mediator md) {		super(20);		kdata = new KidData ("50free.txt");		fillKidList();		med = md;		med.registerKidList(this);		addListSelectionListener(this);	}	    	//----------------------------------	public void valueChanged(ListSelectionEvent ls) {		JList obj = (JList)ls.getSource();		if (obj.getSelectedIndex() >= 0)		med.select();	}		//----------------------------------	private void fillKidList() {		Enumeration ekid = kdata.elements();		while (ekid.hasMoreElements()) {			Kid k =(Kid)ekid.nextElement();			add(k.getFrname()+" "+k.getLname());		}	}}
    텍스트 필드는 그 자체를 mediator에 등록을 하기 때문에 훨씬 간단하다.
public class KTextField extends JTextField {	Mediator med;		public KTextField(Mediator md) {		super(10);		med = md;		med.registerText(this);	}}
    이러한 클래스들 모두의 공통점은 각각의 것들이 Mediator에 대하여 알고 Mediator에게 그것의 존재를 알려줘 Mediator는 적절한 시기에 명령들을 보내 줄 수 있다.

    Mediator 그 자체는 아주 간단하다. 그것은 Copy, Clear 와 Select 메소드를 지원하고 각 컨트롤들을 위해 메소드들을 등록해 둔다:
public class Mediator {	private ClearButton clearButton;	private MoveButton moveButton;	private KTextField ktext;	private KidList klist;	private PickedKidsList picked;		public Mediator() {	}	//------------------------------------	public void Move() {		picked.add(ktext.getText());		clearButton.setEnabled(true);	}		//------------------------------------	public void init() {		Clear();	}		//------------------------------------	public void Clear() {		ktext.setText("");		moveButton.setEnabled(false);		clearButton.setEnabled(false);		picked.clear();		klist.clearSelection();		System.out.println("cleared");	}		//------------------------------------	public void select() {		String s = (String)klist.getSelectedValue();		ktext.setText(s);		moveButton.setEnabled(true);		System.out.println("selected");	}		//------------------------------------	public void registerClear(ClearButton cb) {		clearButton = cb;	}		//------------------------------------	public void registerMove(MoveButton mv) {		moveButton = mv;	}		//------------------------------------	public void registerText(KTextField tx) {		ktext = tx;	}		//------------------------------------	public void registerPicked(PickedKidsList pl) {		picked = pl;	}		//------------------------------------	public void registerKidList(KidList kl) {		klist = kl;	}}
시스템의 초기화

    Mediator를 가장 정교하게 하는 연산자 중의 하나는 요구되는 상황에 대한 모든 컨트롤의 초기화이다. 언제 우리가 프로그램을 시작할 때 각 컨트롤들은 기본 상태에서 알려져 있어야 한다. 왜냐면 이러한 상태들은 프로그램이 진화함에 따라 변경될 수 있기 때문에 우리는 간단히 요구되는 모든 상태에 대해 세팅해 주는 init 메소드를 Mediator에 만들었다. 이 경우에 상태는 Clear 버튼에 의해 이루어지는 것과 같고 우리는 간단하게 이 메소드를 호출할 수 있다 :

public void init() {
    Clear();
}

Mediators and Command Objects

이 프로그램에서 두 개의 버튼은 command 객체들이고 이러한 버튼들을 초기화 할 때 ActionListener로 사용자 인터페이스 프레임에 등록을 하였다. 우리가 앞에서 보았던 것처럼 이것은 간단하게 버튼 클릭 이벤트를 처리한다.

public void actionPerformed(ActionEvent e) {
    Command comd = (Command)e.getSource();
    comd.Execute();
}
대안적으로 우리는 자신의 리스너를 가진 상속 받은 클래스를 등록하여 Mediator에 직접 결과를 전달할 수도 있다.

    그러나 두 가지 모두 Command 패턴 단원에서 보았던 문제들에 대한 해결책 중의 하나이다.

Consequences of the Mediator Pattern

  1. Mediator는 프로그램에서 객체들 사이의 가능한 느슨한 커플링을 만든다. 또 그 밖에 것들이 여러 객체들 사이에서 방해할 수 있는 행동을 줄여줄 수 있다.
     
  2. 간단하게 바꾸거나 Mediator의 하위 클래스로 프로그램의 행위를 바꿀 수 있다.
     
  3. Mediator 접근은 새로운 Colleague를 프로그램의 다른 부분을 변경하는 것 없이 추가할 수 있다.
     
  4. Mediator는 사용자 인터페이스에서 나머지 객체들이나 메소들에 대해 너무 많이 아는 Command 객체의 문제를 해결한다.
     
  5. Mediator는 바꾸기 힘들고 유지하기 힘든 복잡한 덩어리가 될 수 있다. 종종 Mediator에 주어진 책임들을 수정하여 이 상황을 개선할 수 있다. 각 객체는 자신의 일을 수행하고 Mediator는 단지 객체들 사이의 상호작용만 관리한다.
     
  6. 각각의 Mediator는 각각의 Colleague들을 호출할 수있는 메소드를 가지고 있고  각각의 Colleague가 이용하는 메소드들이 무엇인지를 알 수 있도록 작성된 클래스이다. 이것이 다른 프로젝트에서 Mediator 코드가 재사용되는 것을 어렵게 한다. 반면에 Mediator들은 아주 간단한고 이 코드를 작성하는 것이 어떤 방법보다 객체들의 복잡한 상호작용을 관리하는 것 보다 훨씬 더 쉽다.