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

  1. 2011.08.13 [펌] The Facade Pattern
  2. 2011.08.13 [펌] The Decorator Pattern
  3. 2011.08.13 [펌] The Composite Pattern
  4. 2011.08.13 [펌] The Command Pattern

The Facade Pattern

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

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

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

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

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

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

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

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

Building the Facade Classes

    어떻게 데이터베이스를 연결할 것인지 고려해보자. 우리는 우선 데이터베이스 드라이버를 읽어들여야 한다.   

try {
	Class.forName(driver);
} //load the Bridge driver

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

    이 간단한 클래스들은 데이터베이스를 열고, 데이터베이스에 있는 테이블의 이름이나, 열의 이름과 내용, 간단한 쿼리에 의해  표시될 수 있도록 해준다. 

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

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

        ##########3*

Consequences of the Facade

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

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

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

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

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 키르히아이스
,

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이다. 그리고 그 사람은  마케팅과 제조를 담당하는 두사람을 고용하였다. 곧, 각각의 사람은 추가적으로 광고, 선적 기타 등등을 도울 수 있는 사람을 고용했다. 그리고 그들은 회사의 첫 번째 부회장이 되었다. 회사가 계속해서 성장함에 따라, 우리가 아래 그림에서 볼 수 있는 것처럼 구조화 될 것이다:

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

    이제, 그 회사가 성공해서, 그 회사의 각각의 사원은 봉급을 받고, 그 회사의 고용비용을 물어 볼 수 있다. 우리는 모든 사원에 대한 봉급으로서 그 비용을 정한다. 여기에 컴포지트에 대한 이상적인 예가 있다.
  • 각 개인의 고용비용은 각 개인의 봉급이다.
  • 한 부서의 고용비용은 그 부서의 책임자와 그들의 부하직원의  봉급의 합이다.
    우리는 고용인이 부하직원이 있든 없든 간에 정확한 전체의 봉급을 계산하는 하나의 인터페이스를 만들고자 한다.  

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

아래 그림은 최종적인 프로그램이다:

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

    이 구현에서, 비용(전체 봉급 합)은 아래의 버튼에 보여지게 된다. 이 간단한 계산은  메소드가 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를 반환한다. 

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

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

The Command Pattern

    Chain of Responsibility 패턴은 클래스들의 체인들을 따라서 요청들을 진행하지만, Command 패턴은 특별한 모듈로 하나의 요청을 진행한다. 그것은 하나의 객체 내부의 특정한 동작을 위한 하나의 요청을 둘러싸고 알려진 public 인터페이스를 준다. 그것이 수행하게 될 실제적인 동작에 대한 알고 있는 것 없이 요청들을 만들 수 있는 능력을 클라이언트에게 주게 한다. 그리고 어떤 방식으로든 클라이언트 프로그램에 영향을 주는 것 없이 동작을 변경할 수 있도록 한다.

Motivation

자바 사용자 인터페이스를 만들 때, 메뉴 항목들, 버튼들, 그리고 체크 박스와 같은 것들을 제공해야 하고, 프로그램이 무엇을 하는지를 사용자에게 알여 줘야 한다. 사용자가 이러한 컨트롤들 중의 하나를 선택했을 때, 프로그램은 하나의 ActionEvent를 받는다.
File|Open and File|Exit를 선택할 수 있는 메뉴항목과 버튼을 눌렀을 때 배경을 빨강색으로 바꿔주는 간단한 프로그램을 가정해 보자. 이 프로그램은 아래의 그림과 같다.

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

    이 프로그램은 mnuOpen 과 mnuExit를 MenuItem으로 가지는 File Menu로 구성되어 있다. 또 btnRed라 불리는 하나의 버튼을 포함한다. 어떤 것을 눌러도 우리는 다음 코드처럼 actionPerformed 메소드를 이용하여 이벤트를 잡아낼 수 있다.
	
public void actionPerformed(ActionEvent e) {
	Object obj = e.getSource();
	if(obj == mnuOpen)
		fileOpen();	//open file
	if(obj == mnuExit)
		exitClicked();
	if(obj == btnRed)
		redClicked();	//turn red
}
    이 메소드가 부르는 3개의 private 메소드는 :

private void exitClicked() {
	System.exit(1);
}

//-----------------------------------------

private void fileOpen() {
	FileDialog fDlg = new FileDialog(this, "Open a file", FileDialog.LOAD);
	fDlg.show();
}

//-----------------------------------------

private void redClicked() {
	p.setBackground(Color.red);
}
    몇개 안되는 메뉴 항목과 버튼들이 있을 때는 이러한 방식도 괜찮지만, 메뉴 항목이 수 십개가 되고 여러개의 버튼을 가지고 있을 때는 actionPerformed 코드는 꾀나 거대해지게 된다.

The Command Pattern

모든 객체가 자신의 명령을 직접적으로 받게 하는 한가지 방법은 Command 객체를 사용하는 것이다. Command 객체는 항상 액션이 객체내에서 발생했을 때 호출되는 Execute() 메소드를 가지고 있다.   
가장 간단하게, Command 객체는 적어도 다음의 인터페이스를 구현한다.

public interface Command {
	public void Execute();
}
이 인터페이스를 사용하는 목적은 actionPerformed 메소드를 다음과 같이 줄이기 위해서이다.

public void actionPerformed(ActionEvent e) {
	Command cmd = (Command)e.getSource();
	cmd.Execute();
}
그러면 우리는 요구되는 엑션을 수행하는 각각의 객체에 대한 Execute 메소드를 제공할 수 있어, 그 것이 속해 있는 객체내에서 무엇을 할 것인가에 대한 정보를 유지할 수 있다.

    Command 패턴의 중요한 목적은 프로그램을 유지하고 사용자 인터페이스 객체들을 완전히 분리하는 것이고 다른 객체들의 작업에 대해 알 필요가 없다. 사용자 인터페이스는 명령을 받고 Command 객체에게 어떤 종류의 의무든지 알려줄 수가 있다. 사용자 인터페이스는 어떤일을 해야할 지 알려고 하지 않아도 되고 알 필요도 없다.

    Command 객체는 또 리소들이 바로 사용되지 않을 때 명령을 수행하는 프로그램에게 알려 줄 필요가 있을 때 사용되어 질 수 있다. 이러한 경우에서는 나중에 실행되는  queuing 명령들이다.
마지막으로, 취소 요구들을 지원할 수 있기 위해서 연산자들을 기억하는 Command 객체에도 사용되어 질 수 있다.

Building Command Objects

    이와 같은 프로그램을 위한 Command 객체들을 만드는 거에 관한 여러가지 방법이 있고 각각의 방법은 몇가지 이점을 갖는다. 우리는 가장 간단한 방법부터 시작할 것이다 : MenuItem 과 Button 클래스에서 파생 받아 새로운 클래스를 만들고 각각 Command 인터페이스를 구현한다.  

class btnRedCommand extends Button implements Command {
	public btnRedCommand(String caption) {
		super(caption);	//initialize the button
	}
	public void Execute() {
		p.setBackground(Color.red);
	}
	//----------------------------------------
	
class fileExitCommand extends MenuItem implements Command {
	public fileExitCommand(String caption) {
		super(caption);	//initialize the Menu
	}
	public void Execute() {
		System.exit(0);
	}
    이 방법은 확실히 actionPerformed 메소드에서 만들어진 것을 간단하게 호출할 수 있지만, 실행하고자 하는 각각의 동작을 위하여 새로운 크래스를 만들고 인스턴스화 하는 것을 요구한다.

	mnuOpen.addActionListener(new fileOpen());
	mnuExit.addActionListener(new fileExit());
	btnRed.addActionListener(new btnRed());
    우리는 이러한 클래스들에 필요한 파라미터드을 전달하는 대부분의 문제를 그것들의 내부 클래스를 만들어 우회할 수 있다. 이것은 직접 이용할 수 있는 Panel 과 Frame 과 같은 객체들을 만든다.

    그러나, 내부의 클래스들은 명령들이 급증함에 따라 좋은 생각은 아니다. 왜냐면, 어떤 다른 사용자 인터페이스 컴포넌트에 접근하는 그것들 중의 어떤것도 메인 클래스 내부에서 유지해야 하기 때문이다. 이것이 혼란스러운 작은 내부 클래스의 증가로 메인 클래스에 대한 코드는 복잡해 진다.

    물론, 이러한 클래스들에게 필요한 파라미터들을 전달하는 것을 꺼려하지 않는다면 그것들은 독립적으로 될 수 있다. 여기서 우리는 파라미터로 Frame 객체와 Panel 객체를 전달하였다.

	mnuOpen = new fileOpenCommand("Open...", this);
	mnuFile.add(mnuOpen);
	mnuExit = new fileExitCommand("Exit");
	mnuFile.add(mnuExit);
	p = new Panel();
	btnRed = new btnRedCommand("Red", p);
	p.add(btnRed);
두번째 경우에서 우리의 메뉴와 버튼 command 클래스들은 메인 클래스 외부에 존재할 수 있고, 원한다면 파일을 나누어 저장할 수 도 있다.

The Command Pattern in Java

그러나 여전히 이 패턴을 접근하는 두어가지 방법이 있다. 만약 모든 컨트롤을 그 자신의 actionListener 클래스에 주었다면, 각각의 command 객체들을 효과적으로 생성한 것이다. 그리고, 사실, 이것이 자바1.1 이벤트 모델의 설계자들에게 있어서는 실제적이다.
    이 방법을 구현하기 위해 우리는 ActionListener 클래스를 구현한 작은 클래스들을 생성한다.

class btnRed implements ActionListener {
	public void actionPerformed(ActionEvent e) {
		p.setBackground(Color.red);
	}
}	

//------------------------------------------
class fileExit implements ActionListener {
	public void actionPerformed(ActionEvent e) {
		System.exit(0);
	}
}
그리고 일반적으로 리스너로써 그것들을 등록한다.

	mnuOpen.addActionListener(new fileOpen());
	mnuExit.addActionListener(new fileExit());
	btnRed.addActionListener(new btnRed());

Consequences of the Command Pattern

Command 패턴의 주요 단점은 메인 클래스를 어지럽게 하는 작은 클래스들의 급증이다.

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

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