[출처 : http://ohgyun.com/tag/Static%20Method%20Overriding ]
문제:

클래스 A를 상속받는 클래스 B가 있다.
테스트를 위해서 각각의 클래스에 main 메서드를 작성해놨다.

class A {
    public static void main(String[] args) {}
}

class B extends A {
    public static void main(String[] args) {} // overriding 하려고 시도
}

이런 식이다.

이클립스에서 이 내용을 작성하고 있었는데,
분명 B 클래스의 main 메서드는, A 클래스의 것을 오버라이딩한 게 맞을 텐데,
이상하게 메서드 앞에 오버라이드 됐다는 아이콘이 표시되지 않는다.

어라? 스태틱 메서드는 오버라이딩 되지 않는 건가?


해결책:
검색해보니, static 메서드는 Overriding 할 수 없다고 한다.
대신 스태틱 메서드에서의 오버라이딩은 Hiding 이라고 한다.

JVM 이 메서드를 호출할 때,
instance method 의 경우 런타임 시 해당 메서드를 구현하고 있는 실제 객체를 찾아 호출한다. (다형성)
하지만 class method (static method)의 경우, 컴파일 시점에 선언된 타입의 메서드를 호출한다.
컴파일러와 JVM 모두 클래스(스태틱) 메서드에 대해서는 실제 객체를 찾는 작업을 시행하지 않기 때문이다.
(즉, 스태틱 메서드에 대해서는 다형성이 적용되지 않는다)

아래 코드를 가지고 테스트해보면 쉽게 이해가 된다.

    class A {
        public static void classMethod() {
            System.out.println("classMethod() in A");
        }
       
        public void instanceMethod() {
            System.out.println("instanceMethod() in A");
        }
    }
   
    class B extends A {
        public static void classMethod() {
            System.out.println("classMethod() in B");
        }
       
        public void instanceMethod() {
            System.out.println("instanceMethod() in B");
        }
    }
   
    class Test {
        public static void main(String args[]) {
            A a = new B();
            a.classMethod(); // classMethod() in A 가 출력된다.
            a.instanceMethod(); // instanceMethod() in B 가 출력된다.

            // static method 를 포함하고 있는 클래스로 선언할 경우 호출할 수 있다.
            ((B) a).classMethod();
// classMethod() in B 가 출력된다.
        }
    }
  

몇 가지 사용에 대한 팁을 제시하자면,..
    1. 오버라이드된(하이딩 된) 스태틱 메서드를 정확하게 호출하려면  메서드가 포함된 실제 객체로 선언해야 한다.
    2. 웬만하면, 하이딩의 사용은 피하는 게 좋겠다.


상세한 내용은 아래 포스트를 참고하자. (꼭 읽어보길 권한다)
Posted by dlucky

[참조 : http://endlessprogramming.tistory.com/322 ]


MVC 패턴에 대해 알아보죠.



그림 1 MVC Pattern Diagram


<그림 1>에서는 일반적인 MVC 패턴을 다이어그램으로 표현하고 있습니다.

MVC 패턴은 Model, View, Controller 세 개의 컴포넌트로 구성되는데 각 컴포넌트에서 담당하는 책임은 다음과 같습니다.


  • View
    UI 요소를 그려줍니다.
  • Controller
    UI의 사용자 액션에 응답하고 데이터 흐름을 제어합니다.
  • Model
    MVP 패턴의 Model과 마찬가지로 데이터와 상태를 유지하며 데이터 처리 로직을 포함합니다.

MVC 패턴이 MVP패턴과 다른 점은 Presenter 컴포넌트 대신 Controller 컴포넌트가 존재하는 것이죠. Controller는 사용자의 액션 - 예를 들면 버튼 컨트롤을 클릭하거나 키보드를 통해 텍스트를 입력 받는 행위들 - 에 반응하여 적절한 행동을 하는 코드를 포함합니다. 즉, 사용자의 액션에 반응하여 Model의 데이터를 변경하는 역할을 수행합니다.


MVC 패턴이 적용된 대표적인 사례는 MFC(CDocument <-> CView), ASP.NET(ASPX <-> Code Behind), WinForm.NET(Form & Control Design.cs<-> Form & Control .cs <-> Entity or Business Logic .cs) , JSP등이 있겠습니다. 특히 JSP에서는 (자바진영) View와 Controller가 합쳐진 Model 1과 View와 Controller를 명확히 구분하고 View와 Model 사이에 상호작용을 전담하는 역할로서 Controller를 정의합니다.


그림 2 JSP Model 1 architecture


그림 3 JSP Model 2 architecture


Model 1에서는 JSP에서 사용자 Request(Controller)와 Response(View)를 담당하고 Data source의 접근 처리는 JavaBean(Model)에서 담당하게 됩니다.

Model 2에서는 사용자 Request를 Servlet(Controller)에서 담당하고 Response는 JSP(View), Data source의 접근 처리는 JavaBean(Model)에서 담당하게 되죠.


이와 비슷한 모델로 최근 ASP.NET 3.5에서 발표될 MVC Framework를 들 수 있겠습니다. Request URL을 Controller가 분석해서 Model에 데이터를 쿼리(조회, 갱신)하고 적합한 View를 선택해서 Rendering하는 방식입니다.


문제는 View와 모델을 완전히 분리할 수 없다는 것이죠.

JSP의 Model2를 보셔도 JSP와 JavaBean과의 상호작용은 피할 수 없습니다. 역시 ASP.NET의 MVC Framework에서도 Controller에서 Model에 쿼리를 수행한 다음 반환된는 Entity(or Entity List)를 View에 바인딩할 때 Entity 자체를 넘겨주게 되므로 View에서 Model을 의존하게 되는 상황이 발생하게 되죠.


또한 MVC 패턴에서 Model에 연결된 View가 여럿일 경우 Model과 View간(또는 Model을 대신해서 Controller) Observer패턴을 적용하여 Model(or Controller)에서 View로 Notify하는 (Active Model) 방식이 사용되거나 반대로 View에서 Model을 polling(Passive Model)하는 방식이 수행됩니다.


그림 4 MVC passive model


그림 5 MVC active model


그림 6 Using observer pattern to decouple the model from view in the active model


이 프로세스를 살펴봐도 역시 View와 Model의 커플링은 제거하기 힘들어 보이는 군요.

(이런 논의도 있습니다. http://kldp.org/node/70219 )


애초에 MVC패턴이 나온 이유가 뭘까요?

바로 View와 Model의 분리입니다. 쉽게 말해 표현계층과 데이터( + 데이터 처리 로직)를 분리하여 데이터 처리 로직이 중복 코딩되는 것을 막고 로직과 엔티티(데이터)를 재 사용하는데 그 목적이 있습니다. 또한 GUI의 단위 테스트 코드를 작성할 수 있을지에 대한 기대감도 포함합니다.


하지만 MVC패턴에서는 View와 Model간의 의존성을 완벽히 분리할 수 없는데다 패턴의 모호함때문에 해석이 제각각 달라지며 여러가지 변형이 생기게 되었습니다.

그런 와중에 MVP패턴이 마틴 파울러에 의해서 발표되었는데 이 패턴에서는 View와 Model의 완벽한 분리가 이뤄지는 특징이 있습니다. 

MVP 패턴에 대해서는 "MVP(Model-View-Presenter)패턴을 적용한 GUI Architecture 설계" 포스트를 참조하세요

Posted by dlucky

[참조 : http://hiddentrap.tistory.com/95 ]


1. 프로토타입 패턴:

   클래스로부터 인스턴스를 만들지 않고 인스턴스를 복사해서 새로운 인스턴스를 만드는 복제 패턴

 

image 

2. 클래스에서 인스턴스를 만드는 대신 Prototype패턴을 사용하는 이유


  • 종류가 너무 많아서 클래스로 정리할 수 없는 경우 
    비슷하지만 그 유형이 너무 많은 모형의 경우에 모두 각각의 클래스로 만들면 클래스의 수가 너무 많아지기 때문에 소스 프로그램을 관리하기 힘들다.
  • 클래스로부터 인스턴스 생성이 어려운 경우 
    마우스를 사용해서 도형 에디터와 같은 어플리케이션의 경우처럼 사용자가 조작을 해서 만든 도형을 나타내는 인스턴스와 같은 것을 만들고 싶다면 클래스를 사용하는 것이 아니라 인스턴스를 복사해서 만드는 방법이 간단하다.
  • framework와 생성하는 인스턴스를 분리하고 싶은 경우 
    클래스 이름의 속박으로부터 framework을 분리할 수 있다. 소스 내부에 이용할 클래스의 이름이 쓰여있으면 그 클래스와 분리해서 재이용할 수 없게 된다. 소스 파일(.java)이 없어도 재사용할 수 있게 하는 것이 중요하다.
===============================================================================================================

저 위에 코드를 UML을 빌리자면, create()함수에는 interface인 prototype 형으로 인자를 받아 clone을 해주어
객체를 생성해 줄것이다.(new 로 각각 조건에 맞는 객체를 생성해주려고 구현하면 구현해야 하는 종류가 많아 질수록
switch문으로 조건 달아줄 코드가 길어지게 된다.)
 
Posted by dlucky

1. Templete Pattern
    
    상위 클래스의 Templete Method에서 주요 구현을 하고, 하위 클래스에서 나머지 함수들의
    세부 구현을 한다. => 그러면 상속 받은 클래스의 함수들은 각자 다른 식으로 구현 되기 때문에
    서로 다른 결과를 낼 수 있다. 또한 주요 알고리즘 적인 요소는 Templete Method에 구현되어
    있으므로, 상위 클래스만 고치면 빠르게 고칠 수 있다.

2. Hook 함수에 대해서...

    후크는 추상 클래스에서 선언되는 메소드긴 하지만 기본적인 내용만 구현되어 있거나 아무 코드도
    들어있지 않은 메소드 이다. 이렇게 하면 서브 클래스 입장에서는 다양한 위치에서 알고리즘에 끼어
    들 수 있다.   


public abstract class CaffeineBeverage {
    final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        if (customerWantsCondiments()) {
            addCondiments();
        }
    }
   
    abstract void brew();
   
    abstract void addCondiments();
   
    void boilWater() {
        System.out.println("물 끓이는 중");
    }
   
    void pourInCup() {
        System.out.println("컵에 따르는 중");
    }
    // hook method
    boolean customerWantsCondiments() {
        return true;
    }
}



[출처 :
http://iilii.egloos.com/3806897 ]

1. Template Method 패턴은..

전체적인 로직에는 큰 차이가 없지만 일부분만 바뀌는 비스무레한 몇 가지 클래스가 있다고 칩시다. 일부분을 위해서 전체를 새로 작성할 필요는 없지요. Template Method에서는 전반적인 구현은 상위클래스(주로 Abstract로 만듭니다.)에서 담당하고 부분적인 곳의 구체적인 구현은 하위클래스가 담당합니다.

2. 예제

------------- 템플릿 메쏘드가 있는 Abstract Class ---------------
package ch04_TemplateMethod;

public abstract class Worker {
    
protected abstract void doit();
    public final void work(){
        System.out.println("출근");
        doit();
        System.out.println("퇴근");
    }
}
------------- Abstract Class 구현체 1 ---------------------
package ch04_TemplateMethod;

public class Designer extends Worker {
    @Override
    protected void doit() {
        System.out.println("열심히 디자인");
    }
}
------------- Abstract Class 구현체 2 ---------------------
package ch04_TemplateMethod;

public class Gamer extends Worker {
    @Override
    protected void doit(){
        System.out.println("열심히 껨질");
    }
}
------------- 테스트 코드 ---------------------
package ch04_TemplateMethod;

public class Test {
    public static void main(String[] args) {
        Worker designer = new Designer();
        designer.work();
        Worker gamer = new Gamer();
        gamer.work();
    }
}

Worker 클래스의 work()는 내부적으로 abstract 메쏘드인 doit()을 호출하고 있습니다. work() 안에서 전반적인 로직이 수행되고, 로직 중 각각의 특성을 탈 수 있는 부분을 doit() 안에서 해결합니다. doit()은 실제 구현체에서 알아서 구현하면 됩니다.
work() 를 final로 구현한 것은 하위 클래스에서 전체적인 로직 변경을 하지 못하도록 하는 것입니다.

3. Template Method 사용시 고려사항

Template Method는 위험성을 어느 정도 내포하고 있습니다. 바로 전체적인 프로세스가 바뀌는 것입니다. 상위 클래스에서 변동이 일어날 경우 하위 클래스가 안전하리라는 보장은 할 수 없습니다. 상위 클래스에 abstract method가 하나만 추가되어도 모든 하위 클래스는 변경이 불가피합니다. 
나중에 발생하는 작은 변경이 큰 재난을 일으킬 수 있습니다. 이것은 상속이 가지는 위험성입니다.
그래서 Template Method 패턴을 사용할 때는 상위클래스에 대한 심사숙고가 반드시 필요합니다. 
일반적으로는 전체적인 프로세스를 담당하는 로직을 final 메쏘드로 정의하기도 하지만, 프로세스 자체의 변경을 고려해 상속의 여지를 남겨두기 위해 final 메쏘드로 정의하지 않기도 합니다.
또 한가지는 하위 클래스의 메쏘드들은 외부에서 직접 호출되지 않고 상위 클래스의 Template Method에서 호출됩니다. 그래서 주로 protected 로 선언됩니다. 그런 이유로 외부의 호출과 구체적인 구현체의 메쏘드가 실행되기까지의 과정을 쉽게 파악하기가 어렵습니다. 문제가 생겼을 때 추적이 어려울 수도 있다는 것이죠.

4. JAVA API에 있는 Template Method

아마 JDK안에 가장 많이 들어 있는 패턴 중 하나가 Template Method일 겁니다. 
Servlet 을 개발할 때, HttpServlet을 상속 받아 doGet()  doPost() 를 구현합니다. HttpServlet의 service() 에서 하위구현체의 doGet()이나 doPost() 등으로 분기를 시킵니다.(그 외에도 do머시기하는 메쏘드가 있지만 생략합니다.) Template Method의 전형적인 사용법 중 하나입니다. 분기를 담당하는 부분은 상위클래스에 구체적으로 구현하고, 분기된 이후의 행동은 하위구현체에 떠 넘기는 방법이죠.

HashSet이라는 Set의 구현체를 아시죠? 얘는 Set이니까 중복 데이터를 요소로 가지지 않습니다. 그럼 '같다 다르다'의 기준은 뭘까요? 내용이 같으면 될까요? 아니면, 실제 레퍼런스가 같아야 할까요?
이름에 나와 있듯 hash 값이 일단 같아야 합니다. hash값은 Object의 hashCode() 메쏘드를 이용하여 체크합니다. 그리고 나서 또 Object의 equals() 메쏘드를 호출합니다. 그래서 Set에 넣을 요소에 대해서는 hashCode() 메쏘드와 equals() 메쏘드가 잘 구현되어있어야 합니다. 그렇지 않으면, 중복된 데이터가 삽입될 수 있습니다.
HashSet의 경우는 위에서 설명한 Template Method와는 좀 다릅니다. 상위클래스와 하위클래스의 상관관계 같은 게 없죠. 다만 나도 모르는 사이에 내가 구현한 메쏘드가 호출될 수 있기 때문에 Template Method가 될 수 있습니다.(HashSet의 add(SomeClass) 메쏘드는 SomeClass의 hashCode()와 equals()를 호출합니다. )
정확히 말하면 Set.add(SomeClass) 메쏘드는 Set.contains(SomeClass) 메쏘드를 호출하고 그 안에서 다시 SomeClass.hashCode()와 SomeClass.equals(SomeClass) 를 호출합니다. ( 중간에 좀 더 복잡한 과정이 있지만, 설명할 필요는 없으므로 생략합니다. )
여기서 UI관련 각종 EventListener들도 그런 맥락에서 Template Method라고 볼 수 있습니다. event 발생에서 리스너까지의 과정을 알 필요가 없습니다. 대략 어떤 이벤트를 발생시키면, 어떤 이벤트 리스너한테 전달된다 정도만 알면 되죠. 이벤트 핸들링에는 그 외에도 여러가지 패턴들이 적용되어 있습니다.


Posted by dlucky
[ 참조 : http://blog.naver.com/newsdu/80117219575 ]
[ 참조 : Head First Design Pattern ]

1. 해석자 패턴 => 언어를 일정한 해석 방법을 통해서 해석한 뒤, 그에 맞는 동작을 하게끔 구현
                         컴파일러 문법 등을 생각 하면 쉽다.

2. 간단한 이해

   우리가 어떤 수동적인 반복 작업을 할 때 매크로라는 기법을 쓴다. 근데 사용자는 C언어, WinAPI 언어를 잘 모른다.
   근데 만약 화면의 특정 좌표로 0.00001초만에 이동하여 클릭하는 행위를 하고 싶다고 가정한다.

   SendMessage(hGameWnd, WM_LBUTTONDOWN, MK_LBUTTON, xPos | (yPos <<16));

   이걸 일일이 사용자가 방법을 익혀서 사용한다는 것은 참 부담스럽다.

   클릭하기 x, y
   
   이런식으로 간단하게 입력하여 사용하기를 원한다.
   프로그래머는 저렇게 입력이 들어오면 저런 기능이 수행되게 하는 것은 쉽다.
   입력된 문자들을 공백토큰 기준으로 나누고, 토큰1이 '클릭하기'이면 2,3번을 옵션으로 위의 C 문장을
   구성하면 된다. 근데 문제는 이렇게 단일 기능만 있다면 상관 없지만 '클릭하기'를 만든 김에 사용자
   편의를 위하여 비슷한 명령어와 옵션을 100개 만든다고 한다. 그럼 그것을 일일이 하드코딩하는 것
   보다 더 넓은 시야에서 문장을 바라볼 필요가 있다.

   [명령어] [인수],[인수]

   형태가 이렇다. 만약 100개중 50개가 저런 형태라면 명령어 클래스와 인수 클래스를 만들어 명령어
   클래스는 명령어에 대해서만 해석하고, 인수 클래스는 어떠한 종류의 인수인지만 해석하여
   저장해둔다면 그 두 클래스 모두 표현 클래스를 부모에 두고 복합체 패턴으로 결합하여 명령을
   수행만 하면 끝이다. 만약 +,- 이런 [수식]이 필요해졌다고 하면 수식 클래스에 표현 클래스를 상속하여 작성하면 됨.
   이렇게 토큰을 종류별로 나눠 클래스화 하여 각 종류마다 분리하여 해석한 후 명령을 수행 하는 것이 해석자 패턴 컨셉.



   3. 인터 프리터의 장점
   
        - 각 문법 규칙을 클래스로 표현하기 때문에 언어를 쉽게 구현할 수 있다.
        - 문법이 클래스에 의해 표현되기 때문에 언어를 쉽게 변경하거나 확장할 수 있다.
        - 클래스 구조에 메소드만 추가하면 프로그램을 해석하는 기본 기능외에 예쁘게 출력하는 기능이라던가,
           더 나은 프로그램 확인 기능 같은 새로운 기능을 추가 할 수 있다.

    4. 인터 프리터의 활용법 및 단점
  
        - 간단한 언어를 구현할 때 인터프리터 패턴이 유용하게 쓰인다.
        - 문법이 간단하고 효율보다는 단순하게 만드는 것이 더 중요한 경우 유용하게 쓰인다.
        - 스크립트 언어 및 프로그래밍 언어에서 모두 쓸 수 있다.
        - 문법 규칙의 개수가 많아지면 아주 복잡해진다는 단점이 있다, 그런 경우, 파서/컴파일러 생성기를를 쓰는 것이 낫다.
        - 복잡한 스크립트 구문까지 지원하게 만들려면 그에 드는 비용이 프로그램 전체에 드는 비용과 비슷할 정도로 되어버림
Posted by dlucky
- Visitor 패턴은 간단히 말해서, 복잡한 데이터 구조 (다중 트리구조 등) 속을 하나씩 방문해 가면서 해당하는 작업을 수행해서
   일정 조건이 되면 방문을 마친다.
- 데이터 구조 생성 -> 복잡한 데이터 구조 속에서 원하는 값을 찾아내기 위한 Vistor 생성 -> 데이터 구조 클래스에서
   생성한 Vistor를 accept() 함 -> Vistor는 그 순간 데이터 구조 Components들을 돌아다니며 원하는 값을 찾거나 행동을 함
   -> 일정한 Visit 조건이 완료 되면 방문을 종료함(Visitor에는 원하는 값이 들어 있거나, 방문하면서 원하는 액션을 취함)

================================================================================================================
[참조 : http://iilii.egloos.com/4906850]

1. Visitor 패턴은..

복잡한 구조체 안을 돌아다니면서 어떤 일을 해야 할 경우가 있습니다. Visitor는 어떤 구조체에 대해 그 안을 돌아다니면서 어떤 일을 하는 것입니다. 이 때, 구조체 1개에 하는 일이 딱 1개라는 보장은 없습니다. 하나의 구조체에 대해 다양한 일들을 할 수 있습니다. 하고 싶은 일이 추가된다고 해서 구조체를 변경하는 것은 무리입니다. 이런 때는 Visitor를 추가하면 됩니다. 예제에서는 PC의 디렉토리-파일 구조에 대해 야동을 찾는 일을 하는 Visitor를 구현해보았습니다. 

2. 예제

--------- Component, Composite, Leaf 등은 Composite 패턴 설명에 썼던 것을 거의 그대로 사용했습니다. 바뀐 부분은 색깔 처리했습니다. 처리한 부분만 보시면 됩니다.


package ch16_Visitor;
import java.util.ArrayList;
import java.util.List;

public abstract class Component implements Acceptor{
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    private String componentName;
    protected List<Component> children = new ArrayList<Component>();
    public Component(String componentName) {
        this.componentName = componentName;
    }
    public String getComponentName() {
        return componentName;
    }
    public abstract void add(Component c);
    public List<Component> getChildren(){
        return children;
    }
}

package ch16_Visitor;
public class Composite extends Component {
    public Composite(String componentName) {
        super(componentName);
    }
    @Override
    public void add(Component c) {
        children.add(c);
    }
}

package ch16_Visitor;
public class Leaf extends Component{
    public Leaf(String componentName) {
        super(componentName);
    }
    @Override
    public void add(Component c) {
        throw new UnsupportedOperationException();
    }
}
------------------ Visitor를 받아들일 수 있는 구조체 ---------------- 
package ch16_Visitor;

public interface Acceptor {
    
void accept(Visitor visitor);
}
------------------ Acceptor를 방문하는 Visitor---------------- 
package ch16_Visitor;

public interface Visitor {
    void visit(Acceptor acceptor);
}
------------------ 야동 찾는 YadongFinder ---------------- 
package ch16_Visitor;
import java.util.ArrayList;
import java.util.List;
public class YadongFinder implements Visitor {
    private List<String> yadongList = new ArrayList<String>();
    private List<String> currentList = new ArrayList<String>();
    public void visit(Acceptor acceptor) {
        if (acceptor instanceof Composite) {
            Composite composite = (Composite) acceptor;
            currentList.add(composite.getComponentName());
            List<Component> children = composite.getChildren();
            for (Component component : children) {
                component.accept(this);
            }
            currentList.remove(currentList.size()-1);
        }else  if (acceptor instanceof Leaf) {
            Leaf leaf = (Leaf) acceptor;
            doSomething(leaf);
        }
    }
    protected void doSomething(Leaf leaf){
        if (isYadong(leaf)) {
                String fullPath = getFullPath(leaf);
                yadongList.add(fullPath);
            }
    }
    protected String getFullPath(Leaf leaf) {
        StringBuilder fullPath = new StringBuilder();
        for (String element : currentList) {
            fullPath.append(element).append("\\");
        }
        return fullPath.append(leaf.getComponentName()).toString();
    }
    private boolean isYadong(Leaf leaf) {
        return leaf.getComponentName().endsWith(".avi");
    }

    public List<String> getYadongList() {
        return yadongList;
    }
}
------------------ 테스트 클래스 ----------------  
package ch16_Visitor;

public class Test {
    public static void main(String[] args) {
        Composite main = createComposite();
        YadongFinder visitor = new YadongFinder();
        visitor.visit(main);
        for (String string : visitor.getYadongList()) {
            System.out.println(string);
        }

    }

    private static Composite createComposite() {
        Composite main = new Composite("C:");
        Composite sub1 = new Composite("Program Files");
        Composite sub2 = new Composite("WINDOWS");
        Composite sub11 = new Composite("Pruna");
        Composite sub21 = new Composite("system32");
        Composite sub111= new Composite("Incoming");

        Leaf leaf1111 = new Leaf("강호동 닮은여자-짱이쁨.avi");
        Leaf leaf1112 = new Leaf("EBS야동특강.avi");
        Leaf leaf211 = new Leaf("야메떼-다이조부.avi");
        Leaf leaf212 = new Leaf("이건 야동아님.jpg");
        
        main.add(sub1);
        main.add(sub2);
        sub1.add(sub11);
        sub2.add(sub21);
        sub11.add(sub111);

        sub111.add(leaf1111);
        sub111.add(leaf1112);
        sub21.add(leaf211);
        sub21.add(leaf212);
        return main;
    }
}
---------------- 테스트 결과 -------------
C:\Program Files\Pruna\Incoming\강호동 닮은여자-짱이쁨.avi
C:\Program Files\Pruna\Incoming\EBS야동특강.avi
C:\WINDOWS\system32\야메떼-다이조부.avi

위의 예제에서 중요한 것은 Visitor의 visit(Acceptor) 와  Acceptor의 accept(Visitor)  입니다.

Visitor는 visit(Acceptor) 를 가지고 있고, Acceptor는 accept(Visitor) 를 가지고 있습니다. 둘의 차이가 헤깔립니다. 게다가 accept(Visitor) 를 구현해 놓은 것을 보면 아래와 같이 그냥 Visitor한테 자기 자신을 던져버리는 게 하는 일의 전붑니다.

public void accept(Visitor visitor) {
    visitor.visit(this);
}

이렇게 해 놓은 이유는 구조체를 돌아다닐 수 있게 하기 위한 것입니다. 실제로 구조체를 돌아다니는 일은 Visitor에서 담당하게 됩니다. 만약 이렇게 해놓지 않았다면, Visitor 안에서 구조체를 돌기 위해 재귀적인 호출을 해야만 복잡한 구조를 다 돌 수 있습니다. YadongFinder의 visit(Acceptor) 를 보면, 재귀적인 호출은 없습니다. 
일반적으로 accept(Visitor)의 구현은 위와 같으며 달라질 일이 거의 없습니다.

Visitor의 visit(Acceptor)나 Acceptor의 accept(Visitor) 중 하나는 구조체를 도는 역할을 해야합니다. 구조체를 도는 역할은 Visitor의 visit(Accept)에 맡기는 것이 좋습니다. 구조체를 돌면서 하는 일 뿐만 아니라 "구조체를 도는 방법"도 다른 게 할 수도 있기 때문입니다. 위의 예제에서 YadongFinder는 아무래도 엄마가 짠 것 같습니다. 만약에 아들이 짰다면 구조체를 돌 때 "C:\Program Files\Pruna\Incoming\" 과 같은 비밀스러운 디렉토리는 슬쩍 뛰어넘는 로직을 짤 수 있었겠지요.

그러나 일반적으로 순화하는 로직은 거의 바뀌지 않습니다. 위의 예제에서는 YadongFinder를 상속 받아 doSomething(Leaf) 만 override 하면 뭔가 새로운 Visitor를 만들 수 있습니다.

3. 기타

visit(Acceptor) 안 쪽에서 instance of 로 어떤 클래스인지를 찾아냅니다. 이것은 visit(Composite) 와 visit(Leaf)로 분리시켰더라면 굳이 instance of를 쓸 필요가 없었을 것입니다. 하지만, 그렇게되면 Acceptor라는 인터페이스가 무의미해집니다.

Visitor와 Acceptor는 매우 밀접하게 묶여있습니다. 하지만 사실 Visitor의 구현체와 구조체 사이도 꽤 끈끈하게 묶여있습니다. YadongFinder 안에서 instance of로 체크한 것은 전부 구조체에서 정의된 클래스들(Composite, Leaf) 입니다.

테스트 코드의 YadongFinder를 선언하는 부분을 보면,
YadongFinder visitor = new YadongFinder();  와 같이 되어있습니다. 왜
Visitor visitor = new YadoingFinder(); 라고 인터페이스로 정의를 하지 않았을까요?

YadongFinder의 getYadongList() 부분이 포인트입니다. visitor는 구조체를 돌아다니면서직접 일을 할 수도 있습니다.( 예를들어, YadongFinder를 조금만 수정하면 YadongRemover 로 만들 수도 있습니다.) 하지만 돌아다니면서 뭔가를 수집하는 것과 같이 직접 구조체를 수정하지 않고 단지 정보만 수집하는 경우가 있는데, 그런 경우는 수집한 정보를 다시 뽑아서 사용할 수 있는 방법을 제공해야 합니다. Test 클래스에서 야동 리스트를 찍는 부분을 보시면 됩니다.

Posted by dlucky
- 책임을 하나의 객체만 지는 것이 아니라, 하나의 객체가 처리 하지 못하는 것이면 다음 객체로 넘길 수 있도록
  책임을 사슬처럼 떠넘기는 것이다.
- Observer Pattern 에서 Chain of Responsibility를 적용하면 가로로 넘긴다는 것이 아니라, 하나의 이벤트를 객체가 받았을
때, 그 객체가 처리하지 못하면 다음 객체로 넘겨주도록 구현 되게끔 만든다는 것이다. (Observer는 등록된 모든 객체에
동시에 모두 뿌려줌 - 그 뿌려준 객체 각각에 Chain of Responsibility를 적용할 수 있다는 뜻임)

===============================================================================================================
[ 출처 : http://iilii.egloos.com/3863886 ]
1. Chain of Responsibility 패턴은..

오션스 일레븐과 같은 류의 영화를 보신 적이 있죠? 전문가들이 몇 명 있습니다. 그러나, 그 전문가들은 할 수 있는 일이 극히 제한되어 있죠. 예를 들어, 해커가 격투에 능하진 않습니다. 해커는 단지 해킹에만 능합니다. 그들은 각각은 할 수 있는 일들이 제한적이지만, 모여있으면 세상만사 다 해결합니다. 각각의 전문가들이 자기가 할 수 있는 일만 하면 되거든요. 만약에 그들 모두가 해결할 수 없는 문제가 발생하면... 오션스 투엘브가 되고, 오션스 써틴이 되고 하면 됩니다. 또 영입하면 되죠 멀..
Chain of Responsiblity 패턴에서는 문제 해결사들이 한줄로 쫙 서있다가 문제가 들어오면, 자기가 해결할 수 있으면 해결하고, 안 되면 다음 해결사에게 문제를 넘겨버립니다.

2. 예제

------------------ 전문가: 상위 클래스 ---------------

package ch09_ChainOfResponsibility;
public abstract class Expert {
    
private Expert next;
    protected String expertName;
    public final void support(Problem p){
        if (solve(p)) {
           System.out.println(expertName+ "이(가) " + p.getProblemName()  +"을(를) 해결해 버렸네.");
        }else{
            if (next != null) {
                next.support(p);
            }else{
                System.out.println(p.getProblemName() + "은(는) 해결할 넘이 없다.");
            }
        }
    }
    public Expert setNext(Expert next){
        this.next = next;
        return next;
    }
    protected abstract boolean solve(Problem p);
}

----------- 전문가들이 풀어야할 문제 클래스 -----------

package ch09_ChainOfResponsibility;
public class Problem {
    private String problemName;
    public Problem(String name) {
        this.problemName = name;
    }
    public String getProblemName() {
        return problemName;
    }
}

--------------- 첫번째 전문가 파이터! --------

package ch09_ChainOfResponsibility;
public class Fighter extends Expert {
    public Fighter(){
        this.expertName = "격투가";
    }
    @Override
    protected boolean solve(Problem p) {
        return p.getProblemName().contains("깡패");
    }
}

--------------- 두번째 전문가 해커! --------

package ch09_ChainOfResponsibility;
public class Hacker extends Expert {
    public Hacker(){
        this.expertName = "해커";        
    }
    @Override
    protected boolean solve(Problem p) {
        return p.getProblemName().contains("컴퓨터");
    }
}

--------------- 세번째 전문가 카사노바! --------

package ch09_ChainOfResponsibility;
public class Casanova extends Expert {
    public Casanova(){
        expertName = "카사노바";
    }
    @Override
    protected boolean solve(Problem p) {
        return p.getProblemName().contains("여자") || p.getProblemName().contains("여성");
    }
}

----------------- 테스트 클래스 ------------------

package ch09_ChainOfResponsibility;
public class Test {
    public static void main(String[] args) {
        Problem[] problems = new Problem[5];
        problems[0] = new Problem("덩치 큰 깡패");
        problems[1] = new Problem("컴퓨터 보안장치");
        problems[2] = new Problem("까칠한 여자");
        problems[3] = new Problem("날렵한 깡패");
        problems[4] = new Problem("폭탄");
        
        Expert fighter = new Fighter();
        Expert hacker = new Hacker();
        Expert casanova = new Casanova();
        
        fighter.setNext(hacker).setNext(casanova);
        
        for (Problem problem : problems) {
            fighter.support(problem);
        }
    }
}

--------------- 결과 ----------------

격투가이(가) 덩치 큰 깡패을(를) 해결해 버렸네.
해커이(가) 컴퓨터 보안장치을(를) 해결해 버렸네.
카사노바이(가) 까칠한 여자을(를) 해결해 버렸네.
격투가이(가) 날렵한 깡패을(를) 해결해 버렸네.
폭탄은(는) 해결할 넘이 없다.


등장인물들은 전부 테스트 클래스에 있습니다. 5개의 문제점들이 있고, 3명의 전문가들이 있죠. 테스트 클래스에서는 어떤 전문가가 어떤 문제를 해결하는 지는 관심 없습니다. 
"문제는 해결만 되면 된다!"가 클라이언트인 테스트 클래스의 입장입니다.

Expert 클래스는 마치 Decorator 패턴 처럼 Expert를 멤버 변수로 가지고 있습니다. 그러나 Decoarator와는 달리 그 값이 null일 수도 있습니다. 다음 전문가가 없을 수도 있는 거죠. 위의 코드에서는 casanova가 마지막 전문가입니다. 즉, casanova는 next라는 변수 값이 null입니다. 
일반적인 set머시기 하는 메쏘드들은 리턴 타입이 void인데, 여기서는 리턴 타입이 Expert입니다. 예제코드처럼 전문가 그룹을 연결시키는 코드를 한줄로 만들기 위해서입니다. 만약 리턴 타입이 void였다면, 황토색 부분은 아래와 같이 두 줄로 바뀔 것입니다.

fighter.setNext(hacker);
hacker.setNext(casanova);

Expert 클래스의 support() 가 하는 일은 자기가 해결할 수 있으면 하고, 못하면 다음 전문가한테 넘기고, 떠넘길 다음 전문가가 없으면, 못한다고 생떼를 쓰는 겁니다. 내부적으로 sovle()메쏘드를 호출합니다.
solve()는 각각의 개별 클래스별로 자기가 해결 가능한지 불가능한지를 판단하는 매쏘드입니다. 당연히 구체적으로 기술해야 하므로 하위 객체에 떠넘깁니다. 

3. Chain of Responsibility의 특징

위의 예제에서는 폭탄 앞에 전문가들이 좌절해야 했습니다. 기존에 있던 애들은 그대로 두고, 폭탄전문가를 한 명 영입하면 일이 해결될 것 같습니다. 
폭탄전문가 클래스를 새로 만들어서 테스트 클래스에 넣어주면 일이 해결됩니다. 또 별로 쓸모 없는 전문가를 영입했을 때는 짜르기도 쉽습니다. 전체적인 로직이 바뀌지 않습니다.

템플릿 메쏘드가 숨어있습니다. 테스트 클래스에서는 각 전문가클래스의 solve() 메쏘드를 호출한 적이 없지만, 내부적으로 호출이 됩니다.

문제가 나타났을 때 어떤 전문가가 해결할 것인지 단번에 결정이 되지 않습니다. 일단 모든 문제는 fighter 객체를 거쳐갑니다. 맨 앞에 있으니까요. 따라서 전문가 객체의 순서가 전체적인 수행 속도에 영향을 끼칠 수 있습니다. 
가능한한 일반적인 문제해결사들을 앞쪽에 세워두는 게 좋습니다.

4. JAVA API에 있는 Chain of Responsibility

JAVA 1.0의 GUI 에서는 Chain of Responsibility를 사용했었다고 하는군요. 이벤트가 발생했을 때 자기가 해결할 수 있는 지 보고 해결이 안되면 상위 컴포넌트로 던졌다네요. (확인한 적은 없습니다만, 대충 말은 되는 것 같군요.)
Posted by dlucky
1. Composite Pattern의 간략한 설명과 목적:

[출처 : http://blog.naver.com/PostView.nhn?blogId=gamediz&logNo=20042595126 ]

1)    정의

부분-전체 계층을 나타내기 위해 복합 객체를 트리 구조로 만든다. 컴포지트 패턴은 클라이언트가 개별적 객체와 복합객체 모두를 동일하게 다루도록 한다..

 

복합체 패턴은 개체와 개체군을 동일하게 취급하여 다루기 위한 패턴이다.

하나의 개체와 하나의 개체군을 함께 다루기 위해서는 어떻게 해야 할까? 라는 필요에 의해서 만들어진 패턴이라고 볼 수 있다.

 

2)    예제

다음과 같이 A, B, C, D라는 객체가 있다.

이것들을 컨트롤 하는 과정을 통해 복합체를 설명해보겠다.

 

  

 

1 ~ 4는 객체 컨트롤 과정이다.

1번은 A, B, C, D라는 객체를 놓았다. (아무 작용없는 상태)….

2번은 B를 골라서 양방향으로 쭉 늘였다. 이것은 객체 하나에 대한 컨트롤이다.

3번은 A, B, C, D 객체를 그룹화 해서 한방향으로 쭉 끌었더니 한꺼번에 커졌다.

4번은 B, C, D는 그룹이고, A는 단일 객체인데 이 것들을 한꺼번에 선택하여 이동시키거나 할 수 있다는 것을 보여주는 그림이다.

 

복합체는 3번과 4번의 과정을 행할 수 있도록 만들어 주는 패턴이라고 할 수 있다.

크기, 색깔, 모양이 다른 A, B, C, D 4개의 객체를 그룹화 하여 컨트롤 해줄 수도 있고, 단일 객체로 개별 컨트롤도 가능하며, 더불어 단일객체와 선택되어 있는 객체를 함께 컨트롤 할 수도 있는 방식 그런것이 바로 복합체 패턴이라고 할 수 있다.

 

한쪽은 그룹에 대한 추상화, 한쪽은 도형에 대한 추상화를 추상화를 담당하고 그룹을 옮기면 그룹안에 있는 물건들도 재배열되는 구조를 가졌다고 할 수 있다.

 

3)    게임에서의 활용

스타크래프트를 보면 유닛을 하나씩 컨트롤 할 수도 있지만, 드래그 하여 다수의 개체를 선택하여 하나를 컨트롤 할 때와 같이 컨트롤 할 수 있는데 이런것도 복합체의 예이다.

 

비슷한 예로 윈도우 탐색기에서도 파일/폴더/드라이브는 사실 상위, 하위 구조가 나뉘어져 있는 다른 객체인데, 한꺼번에 복사를 하거나 이동을 하는 등의 기능이 사용되는데 이것도 복합체의 예이다.

 

울티마 온라인에서 가방이라는 요소가 있는데 가방안에 가방을 넣고 그 가방안에 또 가방을 넣고 그 가방안에 또 가방을 넣는 등 가방이라는 객체가 계속해서 겹칠 수 있고 유저는 가장 바깥에 있는 가방하나를 이동하면 그 안에 있는 모든 가방들이 딸려 이동되는 데 이것도 복합체의 한 예라고 할 수 있다.

 

이 처럼 복합체는 보기에 매우 단순해 보이는 패턴이지만, 굉장히 많은 곳에서 응용되는 패턴이다.

2. Composite Pattern의 추가 설명

[출처 : http://devyongsik.tistory.com/198]

컴포지트 패턴을 이용하면 객체들을 트리구조로 구성하여 계층구조로 나타낼 수 있습니다.

중요한 것은 트리구조에서 자식이 있는 노드와 자식이 없는 노드를 구분하지 않고

마치 하나처럼 사용 할 수 있다는 것입니다.

자식이 있는 것을 노드라고 부르고, 없는 것을 잎이라고 부르겠습니다.

컴포지트 패턴에서는 노드와 잎이 하나의 추상 클래스를 상속받습니다.

노드와 잎을 하나처럼(똑같은 방법) 다루기 위함이죠.. 이 말은 뒤에서 다시 언급해보겠습니다.

쇼핑몰을 위해서 카테고리를 만들려고 합니다.

일단 제일 상위에 "전체 카테고리"가 존재하고 그 밑으로

"의류"와 "전자제품" 카테고리가 있습니다. 그리고 "의류" 밑에는 "점퍼" 라는 하위 카테고리가 존재합니다.



public abstract class CategoryComponent {
 public void add(CategoryComponent component) {
  throw new UnsupportedOperationException();
 }
 
 public CategoryComponent getChild(int i) {
  throw new UnsupportedOperationException();
 }
 
 public void print() {
  throw new UnsupportedOperationException();
 }
 
 public void getDeparName() {
  throw new UnsupportedOperationException();
 }
}


카테고리와 그 밑으로 들어가게 될 상품 모두 이 CategoryComponent를 상속해야 합니다.

그래야 노드와 잎을 같은 객체처럼 다룰 수 있습니다.

그리고 메소드마다 exception을 던지는 이유는, 노드 같은 경우는 자식을 가질 수 있기 때문에 add 메소드를 사용하지만

잎 같은 경우는 자식을 가질 수 없기 때문에 add는 사용하지 않는 메소드입니다.

그래서 상위 클래스인 CategoryComponent에서 위와 같이 구현을 해 놓으면 이 클래스를 상속받는 클래스들은

자신이 사용 할 메소드만 구현하면 됩니다.

그러면 Category를 보겠습니다.


import java.util.ArrayList;
import java.util.Iterator;

public class Category extends CategoryComponent {
 private String name;
 private ArrayList <CategoryComponent> components = new ArrayList<CategoryComponent>();
 
 public Category(String name) {
  this.name = name;
 }
 
 public String getName() {
  return name;
 }
 
 public void add(CategoryComponent component) {
  this.components.add(component);
 }
 
 public CategoryComponent getChild(int i) {
  return components.get(i);
 }
 
 public void print() {
  System.out.println("카테고리 이름 : " + getName());
  System.out.println("-----------------------------");
  Iterator<CategoryComponent> iterator = components.iterator();
  while(iterator.hasNext()) {
   CategoryComponent component = iterator.next();
   component.print();
  } 

 }
}



카테고리는 하위 자식을 가질 수 있습니다. 바로 상품들이죠.. 그리고 카테고리는 하위 카테고리도 자식으로 가질 수 있습니다.

노드나 잎이나 모든 CategoryComponent를 상속합니다. 

그리고, print를 보시면...

Iterator를 사용해서 재귀호출로 자기가 가진 자식들의 print()를 호출하고 있습니다.

스택을 그려놓고 저 재귀호출이 어떻게 작동하는지 보시는 것도

좋을 것입니다.


public class Product extends CategoryComponent {
 String name;
 String price;
 
 public Product(String name, String price) {
  this.name = name;
  this.price = price;
 }
 
 public String getName() {
  return name;
 }
 
 public String getPrice() {
  return price;
 }
 
 public void print() {
  System.out.println("상품명 : " + getName());
  System.out.println("가격 : " + getPrice());
  System.out.println("-----------------------------");
 }

}

잎을 구성 할 Product 클래스입니다. 마찬가지로, CategoryComponent를 상속받고 있습니다.

그리고 print()메소드에서는 자식이 없기 때문에 그냥 자기 자신의 정보를 print합니다.

위 Category에서 재귀호출로 불려진 print() 메소드는 자기가 가진 최하위 잎까지 호출되어와서 

그 잎의 print() 메소드부터 다시 실행되며 처리 되는 것입니다.

테스트 클래스입니다.

public class Test {
 public static void main(String[] args) {
  CategoryComponent category = new Category("의류");
  CategoryComponent category2 = new Category("전자제품");
  
  CategoryComponent categoryAll = new Category("전체 카테고리");
  categoryAll.add(category);
  categoryAll.add(category2);
  
  category.add(new Product("스웨터","10000"));
  category.add(new Product("청바지","30000"));
  category.add(new Product("면바지","2000"));
  category.add(new Product("가디건","110000"));
 
  //앗 점퍼 카테고리..
  CategoryComponent category3 = new Category("점퍼");
  category.add(category3);
  category3.add(new Product("지오다노 패딩 점퍼","30000"));
  category3.add(new Product("니 패딩 점퍼","50000"));
  
  category2.add(new Product("아이팟터치","280000"));
  category2.add(new Product("디오스 냉장고","2280000"));
  category2.add(new Product("에어컨","1280000"));
  
  categoryAll.print();
 }
}

트리구조로 상품들을 넣고 있습니다.

전체 밑에 의류와 전자제품이 있고 의류 밑에는 점퍼라는 하위 카테고리가 존재합니다.

그리고 각각의 카테고리는 상품을 가지고 있습니다.

그런데 이것을 모두 출력하는데는 단 한줄의 코드만 있으면 됩니다.

categoryAll.print();

입니다.

카테고리와 상품을 구분해서 출력할 필요도 없습니다.

출력해야 하는 정보는 자기 자신들이 각각 가지고 있을뿐이죠..


사실 Composite 패턴을 사용해서 트리를 제대로 구현하려면 이것보다 더 복잡합니다.


Posted by dlucky
1. Builder 패턴은 똑같은 행동을 하는 Director 부분을 Builder가 무엇이 들어가느냐에 따라 다른 결과물이 나올수 있게 함.

2. Builder 패턴과 State Pattern의 차이점은 State는 상태 클래스가 바뀔 때마다 행동하는 함수가 각각 다를 수 있지만
    Builder 패턴은 동일한 함수를 사용 하되 builder에 따라 다른 결과를 보여준다.

3. Builder 패턴에 대한 좋은 글

[ 출처 : http://annehouse.tistory.com/tag/Builder%20%ED%8C%A8%ED%84%B4 ]
사용자 삽입 이미지


Builder 패턴


Builder 패턴은 하나의 소스객체에서 복잡한 여러개의 객체를 만들 수 있도록 하는 패턴입니다.

따라서, 소스객체는 복잡한 객체를 생성하기 위한 기능을 여러 부분으로 제공합니다.


Builder 패턴의 목적은 복잡한 객체의 생성과정을 표시부분과 분리하여, 생성과정이 같더라도 다른 표현을 할 수 있도록 하는 것입니다.



위 그림과 같이 문서를 작성하는 예제를 살펴보겠습니다.


1. Builder 클래스는 문서를 구성(생성)하는 각각의 단계를 정의하고 있습니다.

    - 타이틀을 작성

    - 문자열을 작성

    - 글머리 기호를 갖는 여러개의 항목 리스트 작성


2. Director는 Builder가 제공하는 메소드만를 이용해서 전체 문서를 구성합니다.


3. TextBuilder와 HTMLBuilder는 Builder 클래스를 상속하여 실제 문서를 구성하는 방법을 각각 다르게 구현합니다. 즉, 문서를 제조하는 과정은 같고, 내용만이 Text 또는 HTML로 작성할 수 있게 됩니다.

예를 들어, 추가로 XML 문서 작성이 필요하다면, Bulder 클래스를 상속하여 XMLBuilder 클래스를 추가하면 생성 과정은 같고 형식이 XML인 문서를 만들 수 있을 것입니다.


4. 문서의 생성 과정은 Builder 클래스가 모두 제공하므로, Builder 클래스는 문서를 생성하는데 필요한 모든 메소드를 충분히 가지고 있어야 합니다.




프로그램 소스


<Builder.java>


public abstract class Builder {
    public abstract void makeTitle(String title);
    public abstract void makeString(String str);
    public abstract void makeItems(String[] items);
    public abstract Object getResult();
}



<Director.java>

public class Director {
    private Builder builder;
    
    public Director(Builder builder) {
        this.builder = builder;
    }
    
    public Object construct() {
        builder.makeTitle("Greeting");
        builder.makeString("아침과 낮에");
        builder.makeItems(new String[] { "좋은 아침입니다.",
                                        "안녕하세요", });
        builder.makeString("밤에");
        builder.makeItems(new String[] { "안녕하세요",
                                         "안녕히 주무세요",
                                        "안녕히 계세요", });
        return builder.getResult();
    }                                         
}



<TextBuilder.java>


public class TextBuilder extends Builder
{
    private StringBuffer buffer = new StringBuffer();
    
    public void makeTitle(String title) {
        buffer.append("================================\n");
        buffer.append("|" + title + "|");
        buffer.append("\n");
    }
    
    public void makeString(String str) {
        buffer.append("*" + str + "\n");
        buffer.append("\n");
    }
    
    public void makeItems(String[] items) {
        for (int i = 0; i < items.length; i++ ) {
            buffer.append("." + items[i] + "\n");
        }
        buffer.append("\n");
    }
    
    public Object getResult() {
        buffer.append("==========================\n");
        return buffer.toString();
    }
}



<HTMLBuilder.java>


import java.io.*;

public class HTMLBuilder extends Builder
{
    private String filename;
    private PrintWriter writer;
    
    public void makeTitle(String title) {
        filename = title + ".html";
        try {
            writer = new PrintWriter(new FileWriter(filename));
        } catch (IOException e) {
            e.printStackTrace();
        }
        writer.println("<html><head><title>" + title + "</title></head></body>");
        writer.println("<h1>" + title + "</h1>");
    }
    
    public void makeString(String str) {
        writer.println("<p>" + str + "</p>");
    }
    
    public void makeItems(String[] items) {
        writer.println("<ul>");
        for (int i = 0; i < items.length; i++ ) {
            writer.println("<li>" + items[i] + "</li>");
        }
        writer.println("</ul>");
    }
    
    public Object getResult() {
        writer.println("</body></html>");
        writer.close();
        return filename;
    }
}



<Main.java>


public class Main {
    public static void main(String[] args) {
        if( args.length != 1 ) {
            usage();
            System.exit(0);
        }
        
        if( args[0].equals("plain")) {
            Director director = new Director(new TextBuilder());
            String result = (String)director.construct();
            System.out.println(result);
        } else if( args[0].equals("html")) {
            Director director = new Director(new HTMLBuilder());
            String filename = (String)director.construct();
            System.out.println(filename + "이 작성되었습니다.");
        } else {
            usage();
            System.exit(0);
        }
    }

    public static void usage() {
        System.out.println("Usage: java Main plain 일반텍스트문서작성");
        System.out.println("Usage: java Main html HTML문서작성");
    }
}

Posted by dlucky

1. 일단 State Pattern은 Strategy Pattern과 UML이나 사용 구조는 같다.
   => 클래스를 바꾸어 넣으면 그 바뀐 클래스에 따라 행동이 달라진다.
2. 허나 그 두 개의 사용 의도는 서로 다르다. ( 그래서 나눠 놓은 것 )

    - State : 상태를 나타내는 클래스를 넣는 것
                (각각 그 해당하는 상태에 맞는 클래스를 넣을 때마다 행동이 달라진다. 조건에 맞는 상태 클래스를 집어 넣음.
    - Strategy : 나중에 확장성을 대비하여 만든 패턴. 현재 장착된 클래스가 나중에 변경되었을 때 그 클래스를 설정한
                     모든 클래스에 한꺼번에 적용할 수 있는 편의성을 제공한다. (적용된 패턴 클래스만 변경하면 됨)
 
Posted by dlucky