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 button

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

    프로그램은 아래와 같다. 마우스가 올라 가면 버튼의 테두리가 그려질 것이다.

        ##########0*        ##########1*

Inheritance Order

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

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

Consequences of the Decorator Pattern

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

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

[펌] The Factory Pattern  (0) 2011.08.13
[펌] The Facade Pattern  (0) 2011.08.13
[펌] The Composite Pattern  (0) 2011.08.13
[펌] The Command Pattern  (0) 2011.08.13
[펌] The Chain of Responsibility Pattern  (0) 2011.08.13
안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,