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

  1. 2011.08.13 [펌] The Chain of Responsibility Pattern
  2. 2011.08.13 [펌] The Builder Pattern
  3. 2011.08.13 [펌] The Bridge Pattern
  4. 2011.08.13 [펌] The Adapter Pattern

The Chain of Responsibility Pattern

    Chain of Responsibility 패턴은 다른 클래스들의 능력에 관해 아는 것 없이 어떤 요청을 조정하려 하는 클래스들을 허용하는 패턴이다.  그것은 이러한 클래스들 사이에 느슨한 커플링을 제공한다; 오직 공통적인 링크는 그것들 사이에서 전달되는 요청이다. 그 요청은 클래스들 중의 하나가 그것을 다룰 수 있을 때 까지 전달된다.

    그러한 체인 패턴 중의 하나의 예는 도움말 시스템이다.
도움말에 대한 영역을 선택했을 때, 컨트롤들이 그 체인의 ID 나 이름을 진행시킨다. 우리가 "New" 버튼을 선택했을 때를 가장해 보자. 만약 첫 번째 모듈이 New 버튼을 조정할 수 있다면 그것을 도움말 메시지를 표시한다. 그렇지 않다면 다음 모듈에 대한 요청을 진행시킨다. 결국, 메시지는 일반적으로 어떻게 버튼들이 작동하는가를 나타낼 수 모든 버튼들의 클래스로 진행된다. 거기에 어떤 일반적인 버튼 도움말이 없다면, 그 메시지는 일반적으로 시스템이 어떻게 동작하는지를 말해줄 수 있는 일반적인 도움말 모듈로 진행된다. 그것조차 없다면 그 메시지는 사라지게 되고 어떤 정보도 나타나지 않는다. 아래의 그림은 이러한 과정을 설명한 그림이다.

        ##########0*
    이 예에서 우리가 관찰할 수 있는 두 가지 의미는 첫째는 체인은 가장 특수한 것에서 가장 일반적인 것으로 구조화 된다는 것이고, 둘째는 모든 경우에서 요청은 책임을 만들어 내는 담보가 없다는 것이다.

Applicability

우리는 다음과 같은 상황에서 Chain of Responsibility를 사용한다.
  • 요청에 대해 조정할 수 있는 하나 이상의 핸들러를 가지고 있고, 사용하는 핸들러를 알아낼 방법이 없을 때. 핸들러는 반드시 체인에 의하여 자동적으로 결정되어야 한다.
  • 명확하게 결정하는 것 없이 여러 객체들 중 하나의 객체에 대한 요청을 이끌러 내려 할 때
  • 요청들을 조정할 수 있는 동적인 객체들의 집합을 수정할 수 있기를 원할 때

Sample Code

    입력된 요청에 따라 결과들을 보여 줄 수 있는 간단한 시스템을 고려해 보자. 이러한 요청들이 있을 수 있다.
  • Image filenames
  • General filenames
  • Colors
  • Other commands
    세 가지 경우에 대해서는 구체적인 요청의 결과를 나타낼 수 있고, 마지막 경우에는 요청한 텍스트 그 자체만 나타낼 수 있다.

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

    위의 예제에서, "ribbons"이라 입력을 하면 "ribbon.jpg" 가 나타나는 걸 볼 수 있다. 그리고 나서, "Sender"라고 입력을 하면, 리스트 박스에서 "Sender.class" 파일일 하이라이트 되는 것을 볼 수 있다. 그 다음, "blue" 라고 입력을 하면 아래의 중앙 패널에 파란색이 칠해지는 걸 볼 수 있다. 마지막으로 파일이름이나 색이 아닌 다른 것을 입력하면 우측이 리스트 박스에 입력한 내용이 추가되는 걸 볼 수 있다.

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

    Responsibility of Chain 프로그램을 작성하기 위해, 먼저 추상 Chain 클래스를 작성한다.
	
public interface Chain {
	public abstract void addChain(Chain c);
	public abstract void sendToChain(String mesg);
	public Chain getChain();
}
    addChain 메소드는 또 다른 클래스를 클래스들의 체인에 추가한다. getChain 메소드는 메시지가 진행될 때 현재 클래스를 반환한다. 이 두 메소드들은 체인을 동적으로 수정하는 걸 가능하게 하고 존재하는 체인의 가운데에 추가적인 클래스들을 추가한다. sendToChain 메소드는 체인안에서 다음 객체에 메시지를 보낸다.

    우리의 Imager 클래스는 JPanel로 부터 상속되고 Chain interface를 구현한다. 이 클래스는 메시지를 받아 루트 이름이 ".jpg"인 파일을 찾는다. 그런 파일이 있으면 표시를 해준다.

public class Imager extends JPanel implements Chain {
	private Chain nextChain;
	private Image img;
	private boolean loaded;

	//------------------------------------------
	public void addChain(Chain c) {
		nextChain = c;    //next in chain of resp
	}

	//------------------------------------------
	public void sendToChain(String mesg) {
		//if there is a JPEG file with this root name
		//load it and display it.
		if (findImage(mesg))
			loadImage(mesg+".jpg");
		else
			//Otherwise, pass request along chain
			nextChain.sendToChain(mesg);
	}
	//------------------------------------------
	public Chain getChain() {
		return nextChain;
	}          

	//------------------------------------------
	public void paint(Graphics g) {
		if (loaded) {
			g.drawImage(img, 0, 0, this);
		}
	}

The List Boxes

    파일 목록과 인식되지 않는 명령들의 목록 모두 JList 박스들이다. RestList 클래스는 체인의 끝이고 어떤 명령이든 나타내어 준다.그러나 편리한 확장을 허용하기 위해 우리는 메시지를 다른 클래스들로 전달할 수 있다. 

public class RestList extends JawtList implements Chain {
	private Chain nextChain = null;
	
	public RestList() {
		super(10);     //arg to JawtList
		setBorder(new LineBorder(Color.black));
	}
	
	public void addChain(Chain c) {
		nextChain = c;
	}
	
	public void sendToChain(String mesg) {
		add(mesg);        //this is the end of the chain
		repaint();
		if(nextChain != null)
		nextChain.sendToChain(mesg);
	}
	
	public Chain getChain() {
		return nextChain;
	}
}        
    FileList 클래스는 꾀나 유사하고, addChain 과 getChain 메소드의 반복을 피하기 위하여  RestList 클래스로부터 파생될 수 있다. 유일한 차이는 리스트가 초기화 될 때 현재 디렉토리에서 파일들의 목록을 읽어 들이고 요청을 받은 파일이 있는지 찾아 본다.

public class FileList extends RestList {
	String files[];
	private Chain nextChain;
	
	public FileList() {
		super();
		setBorder(new CompoundBorder(new EmptyBorder(5,5,5,5), new LineBorder(Color.black)));
		String tmp = "";
		File dir = new File(System.getProperty("user.dir"));
		files = dir.list();
		
		for(int i = 0; i < files.length; i++) {
			for(int j = i; j < files.length; j++) {
		     		if(files[i].toLowerCase().compareTo(files[j].toLowerCase()) > 0) {
				         tmp = files[i];
				         files[i] = files[j];
				         files[j] = tmp;
		      		}
		     	}
		}
		
		for(int i = 0; i < files.length; i++)
			add(files[i]);
	}
	
	//---------------------------------------
	
	public void sendToChain(String mesg) {
		boolean found = false;
		int i = 0; 
		
		while ((! found) && (i < files.length)) {
			XFile xfile = new XFile(files[i]);
			found = xfile.matchRoot(mesg);
			if (! found) i++;
		}
		
		if(found) {
		   	setSelectedIndex(i);
		}
		
		else {
			if(nextChain != null)
		      		nextChain.sendToChain(mesg);
		}
	}
우리가 위에서 소개한 Xfile 클래스는 어떤 파일의 루트이름과 문자열을 비교하기 위한 matchRoot 메소드를 포함하는 File 클래스의 간단한 자식 클래스이다.

    마지막으로, 우리는 그 체인을 형식화하기 위한 생성자에서 이러한 클래스들을 연결시킨다.

//set up the chain of responsibility
sender.addChain(imager);
imager.addChain(colorImage);
colorImage.addChain(fileList);
fileList.addChain(restList);

Consequences of the Chain of Responsibility

  1. 이 패턴의 주요 목적은 객체들 사이의 커플링을 제거하는 것이다. 하나의 객체만 어떻게 다른 객체들에게 요청을 하는지만 알면 된다.
     
  2.  이 접근 방법은 또한 객체들 사이의 분산 responsibilities 에 대해서 유연성을 줄 수 있다. 어떤 객체이든 요청들을 만족할 수 있고, 실행시 체인과 responsibilities를 변경할 수 있다.
     
  3. 장점은 요청을 조정할 수 있는 어떤 객체가 어느것이든 될 수 없다는 것이다. 그러나 체인에서 마지막 객체는 조정할 수 없는 어떤 요청을 버릴 수 있다.
     
  4. 마지막으로, 자바는 다중 상속을 제공하지 않기 때문에, 기본 체인 클래스는 추상클래스보다는 인터페이스를 필요로 한다.

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

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

The Builder Pattern

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

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

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

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

An Investment Tracker

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

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

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

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

    이제, 변수들을 나타낼 인터페이스를 어떻게 생성할 수 있는지 고려해 보자. 우리는 구현 할 필요가 있는 메소드를 정의한 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. 각각의 특수한 빌더는 프로그램의 나머지 부분과는 독립적이다. 이것이 모듈화를 향상시키고 상대적으로 간단하게 다른 빌더들을 추가적으로 만들어 준다 
        빌더 패턴은 일련의 메소드와 객체들로 이루어진 클래스를 반환한다는 점에서는 추상화 패턴과 유사하다. 두 패턴 사이의 중요한 차이는 추상화 팩토리 패턴이 관련된 클래스의 하나의 족을 반환하는데 반해 빌더는 표현해야 하는 데이터에 의존하는 복잡한 객체를 단계적으로 생성한다는데 있다. 

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

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

The Bridge Pattern

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

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

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

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

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

    상위의 프로그래밍 단계에서는 단지 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를 만들어 작업하는 것이 더 나을 것이다. 

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

우리가 가시적인 컴포넌트를 반환하고자 한다면, 스크롤이 있는 패널의 일종으로 만들 수 있다.

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 table
pright.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));
}

정렬된 결과는 다음 그림과 같다.

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

Consequences of the Bridge Pattern

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

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

[펌] The Chain of Responsibility Pattern  (0) 2011.08.13
[펌] The Builder Pattern  (0) 2011.08.13
[펌] The Adapter Pattern  (0) 2011.08.13
[펌] The Abstract Factory Pattern  (0) 2011.08.13
[펌] Summary of Structural Patterns  (0) 2011.08.13
안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,

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 class

public class Closer extends Frame {
	
	public Closer() {
		addWindowListener(new WinAp());
		
		//----------------------------
	}
}

class WinAp extends WidowAdapter {
	public void windowClosing(WindowEvent e) {
		System.exit(0);
	}
	);
}

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

[펌] The Builder Pattern  (0) 2011.08.13
[펌] The Bridge Pattern  (0) 2011.08.13
[펌] The Abstract Factory Pattern  (0) 2011.08.13
[펌] Summary of Structural Patterns  (0) 2011.08.13
[펌] Structural Patterns  (0) 2011.08.13
안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,