이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Interpreter
- 프로그램 안에 다른 종류의 언어로 기술된 명령 문서를 처리하는 interpreter를 작성하는 패턴. 좀 특수한 케이스기는 한데, XML이든 JSON이든 parsing하는 코드의 경우에는 이 패턴을 참조할 만하다.
- [예제] 명령어를 BNF로 정의하였는데, 예제에서는 BNF 형식에 맞춰서 parsing도 하고 parsing된 결과도 구조적으로 가지고 있는다. BNF에서 꺽쇄로 표현되는 정의들은 모두 NonterminalExpression으로 parsing되어 하위 NonterminalExpression을 다시 가지고 있든지 아니면 TerminalExpression을 가지고 있는다.
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Command
- 명령을 객체화 시켜서 관리하는 패턴. Memento와 마찬가지로 프로그램의 undo, redo, history 기능 구현이 목적인데, Memento가 상태를 저장한다면 Command는 명령 이력을 저장 한다.
- ConcreteCommand는 명령을 수행하는데 필요한 최소한의 정보를 가지고 있고 실제로 명령을 실현하기 위해서는 Receiver가 필요하다.
- 명령을 수행하는 지시는 Invoker가 하는데 왜 Invoker가 ConcreteCommand를 직접 보지 않고 Command라는 interface를 보는지는 정확히 알 수 없다. 아마 여러 종류의 command가 있는데 execute() 메소드로 다루기 위함일 것이다.
- [예제] (예제가 조금 어려움) Receiver는 Canvas이고 ConcreteCommand는 point를 저장한다. Client이자 Invoker인 main 메소드는 명령을 drawing 명령을 내리거나 clear를 한다. 특이한 점은 command history를 MacroCommand라 하여 또하나의 ConcreteCommand로 만들었다.
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Proxy
- 진짜 객체를 대신해서 Proxy가 대신 처리해주는 패턴.
- Network이나 Printer같이 진짜 객체를 생성하고 진짜가 처리하는 것을 대신해서 같은 interface의 Proxy가 가벼운 처리를 대신해준다. HTTP의 Proxy가 caching하는 것도 이러한 사례라고 볼 수 있다.
- 처리하지 못하는 어쩔 수 없는 경우에는 진짜 객체를 생성시킨다.
- Proxy와 RealSubject는 Subject interface를 통해 메소드가 동일하기 때문에 Client는 Subject interface를 다루지만 실제로 앞단에서 처리하는 것은 Proxy이다. 즉, Client는 그것이 Proxy에 의해 처리되든 RealSubject에 의해 처리되든 상관할 바 아니다.
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Flyweight
- 객체를 재사용하는 (공유하는) 패턴.
- Flyweight 클래스가 특정한 state/value에 대해서 하나의 instance가 재사용되어도 좋다면 FlyweightFactory 클래스가 이것들의 instance를 map같은데 관리하고 있다가 필요하다고 하는 곳에 제공해준다.
- FlyweightFactory는 싱글톤으로 구현하고 여기서 Flyweight들의 map을 가지고 있는데 key를 통해서 얻어올 수 있다. 만일 특정 key에대해 이미 생성된 Flyweight 인스턴스가 없다면 그때 만들어서 주면 된다.
- 책에는 ConcreteFlyweigth와 UnsharedConcreteFlyweight에 대한 언급은 없는데 중요한 부분은 아닌듯.
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
State
- 상태 변화에 따라서 정의된 모든 action들 - 그림에선 handle() - 에 대한 처리를 각 State가 알아서 진행하는 패턴.
- ConcreteState는 Singleton으로 생성되어 상태에 따라 Context의 state 변수에 assign된다.
- State 변경 판단은 각 ConcreteState에서 한다. (ConcreteState간의 독립성이 조금 훼손된다. 어쩔 수 없다. 중앙에서 상태 관리하면 Mediator 패턴처럼 되는데 이 역시 Context가 모든 ConcreteState를 알아야한다는 단점이 있다.)
- [예제]: Context에 SafeFrame이라는 금고앱. 시간 설정을 하고 주간, 야간 상태에 따라 금고 사용, 비상 벨 사용, 통화 버튼의 동작이 달라진다. ConcreteState는 DayState와 NightState.
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Memento
- 프로그램의 undo, redo, history 기능을 위한 상태 저장 용도로 사용
- Polymorphysm을 사용하지 않는 패턴이다.
- Memento 클래스는 Originator의 상태를 나타내는데, 이것의 생성은 같은 package에 속한 Originator가 한다. (Memento의 생성자는 package private이다) 또 Originator는 외부로부터 Memento를 전달 받으면 그걸로 상태를 복원한다.
- Caretaker는 Originator에게 '상태를 저장해라'라고 명령을 내리고 Memento를 관리한다. 필요하면 저장된 Memento를 Originator에게 전달하면서 '상태를 복원해라'라고 명령을 내린다.
- Originator는 Memento의 생성자와 같은 narrow interface를 사용할 수 있고, Caretaker는 주로 getter와 같은 Mementor의 wide interface를 사용한다.
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Observer
- Android에 많이 쓰는 Observer들과 유사하다. (e.g. GUI의 action listener들)
- Observer interface를 구현한 ConcreteObserver 클래스를 Subject에 등록하면 Subject의 내부 상태 변화나 이벤트 발생시 등록된 Observer들을 모두 호출하여 준다. (Publish-Subscribe 모델이기도 하다)
- Subject의 상태 변화 메소드를 Observer가 호출하는 것과 같이 Subject의 상태를 변화시킬 수 있는데 이 경우 Observer 호출 도중에 다시 Observer를 호출하는 무한 호출 오류가 발생할 수 있다. 따라서 한 turn의 호출이 완료될 수 있도록 상태변수를 두는 것이 좋다.
- Subject도 interface로서 Observer들이 다양한 형태의 ConcreteSubject들의 변화를 통보 받을 수 있도록 한다.
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Mediator
- 다수의 오브젝트들이 서로서로 복잡하게 영향을 미칠 때 중앙에서 동작을 관리하는 패턴
- Mediator는 '중개인' interface인데 회원들(Colleague)들을 관리한다. Colleague interface는 Mediator를 set하고 있다가 상태가 변경되면 Mediator에게 그 사실을 알린다. 그러면 Mediator는 전체적인 상황을 판단해서 모든 회원들에게 동작 변경 (update)를 내린다.
- [예제]: 패스워드 창. Guest/User mode, user name / password 입력 상태에 따라서 버튼이나 텍스트필드가 enable/disable되어야 한다. LoginFrame 창이 Mediator를 구현하고 각 GUI 컴포넌트들 (버튼, 텍스트필드)이 ConcreteColleague가 된다. LoginFrame이 GUI 컴포넌트들을 생성하고 setMediator()를 통해 중개인을 지정한다. GUI 컴포넌트들은 상태변화가 있을 때 LoginFrame에 알리고 enable/disable 명령을 받는다.
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Facade
- 내부의 여러 클래스들을 조합하여 사용하되 외부에는 간단한 하나의 창구만 뚫어주는 패턴이다.
- Polymorphysm을 사용하지 않는 패턴이며 정보은닉(encapsulation)과 관련있다.
- 사용 관계는 오직 Facade에서 내부 클래스로만 되고 역방향은 없다. 중앙에서 조정한다는 측면에서 Mediator랑 비슷하다고 볼 수 있는데 Mediator는 양방향이고 Facade는 단방향이라는 차이가 있다.
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Chain of Responsibility
- 이슈가 발생했을 때 이를 처리하는 Handler들은 자기가 처리할 수 있는 이슈에 대해서만 집중할 수 있다.
- 이때 Handler들 사이에 이슈를 전달하는 방식은 중앙이 아니라 각자가 하는데, successor를 통해 다음 Handler를 사슬처럼 엮는 구조이다.
- 이슈 발생시 Handler들이 차례로 호출되어 처리하고 처리할 수 없으면 다음으로 넘긴다. successor가 없는 마지막 Handler는 최종 error 처리를 하면된다.
- Handler가 resolve()를 false반환하였을 때 next로 iteration시키는 역할을 상위 abstract class가 구현할 수 있다. (그림에서 Handler는 interface지만) 그러면 Client는 사슬의 첫번째 Handler만 가지고 있으면 된다. (아니면 Handler사슬을 가지고 있으면서 iteration시켜주는 제 3의 클래스를 만든다.)
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Visitor
- (내용이 조금 어려움) 데이터 구조와 처리 로직을 분리하려는 목적
- 자료구조에 해당하는 ConcreteElement는 accept()를 구현하고 여기에서 Visitor의 visit() 메소드들 중에 정확한 ConcreteElement를 인자로 받는 메소드를 호출한다.
- 즉, Visitor -> Element.accept() -> Visitor.visit(ConcreteElement) 호출 관계인데 이를 더블 디스패치 (double dispatch)라고 한다. 이렇게 하는 이유는 Element의 세부를 숨기고 Visitor의 처리 로직을 분기시키기 위한 목적이다. (Element가 동작을 결정하되 동작은 Visitor에 구현됨)
- 장점으로 ConcreteVisitor를 추가 정의할 때 Element는 전혀 수정이 없다. 다만 ConcreteElement가 추가되면 모든 기존 ConcreteVisitor에 visit() 메서드를 하나씩 추가해야 된다.
- [예제]: Composite 패턴에서 나왔던 entry, file, directory를 생각해보자. Entry는 Element가 되고 File과 Directory는 ConcreteElement가 된다. 여기에 Vistor interface는 visit(file), visit(directory)의 두 가지 메소드를 정의한다. Composite 패턴에서는 File과 Directory가 print()와 같은 처리로직이 각각 들어가 있는 반면, 여기서는 ListVisitor가 처리로직을 가지고 있다.
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Iterator
- Java Collections에서 많이 사용되는 Iterator들의 패턴. 집합을 순서대로 지정하면서 전체를 처리할 수 있도록 한다.
- Iterator를 제공하는 interface는 Aggregate인데 Java에서 Iterable에 해당한다.
- 그것에 의해 획득된 Iterator는 next(), hasNext()와 같은 표준화된 메서드를 제공한다. 사용하는 측에서는 실제로 어떤 ConcreteInterator가 생성되었는지 알 필요 없이 Iterator iterface에 정의된 해당 메서드들만 사용하면 된다.
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Decorator
- 원래의 오브젝트에 장식(덧붙이기)를 계속해서 해나갈 수 있는 패턴으로 장식과 내용물을 동일시 한다는 점에서 Composite 패턴과 유사하다.
- 차이점은 구상 클래스가 Leaf, Composite 두 유형이 아니라 ConcreteDecorator 하나이다. (물론 실제 구상 클래스는 여러 개) 뿐만 아니라 Decorator-ConcreteDecorator보다 한 단계 더 위가 있는데 (여기서는 Component) 덕분에 Decorator 계통이 아닌 ConcreteComponent도 있다. 그래서 ConcreteComponent가 장식물들 가장 안쪽의 내용물이 된다.
- [예제] StringDisplay(=ConcreteComponent)를 ConcreteDecorator인 SideBorder, FullBorder들이 겹겹이 둘러싸아 장식하는 코드
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Composite
- 그릇과 내용물을 동일하게 취급하여 재귀적인 처리가 가능하게 하는 패턴
- Composite이라는 그릇은 Component를 담을 수 있는데 Component는 Composite이라는 그릇도 되고 Leaf라는 최종 내용물도 된다.
- 예를 들어, Entry(=Component), Directory(=Composite), File(=Leaf)라고 가정해보자 Entry에 정의된 getSize()라는 메소드는 File에서는 실제 file size를 반환하고 Directory에서는 하위 Entry들의 getSize() 총합으로 구현하면 된다. (재귀적 호출)
- 만일 Leaf는 처리할 수 없는 메소드가 있다면 Entry를 abstract class로 선언하고 모든 메소드에 Exception을 던지게 만들어도 된다.
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Strategy
- 기술적으로는 전형적인 polymorphysm이고 위임을 사용한다는 특징이 있다. 의미적으로는 알고리즘(전략)을 외부에서 정의해서 교환 가능하다는 특징이 있다.
- Template Method나 Bridge 패턴이랑 유사.
- Strategy에는 전략을 수행할 execute()가 정의되어 있으며 필요하다면 내부 전략을 수립하는 데 도움이되는 feedback이나 data들을 넣어주는 메소드도 정의될 수 있다.
- ConcreteStrategy는 보통 싱글톤으로 구현한다.
- 전략을 사용하는 Context는 Strategy를 사용하는데 이때 위임의 방식을 사용한다. (동일한 메소드 이름을 갖는 경우도 있다)
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Bridge
- 기술적으로는 전형적인 polymorphysm이고 위임을 사용한다는 특징이 있다. 의미적으로는 기능을 상속하는 클래스 계층으로부터 구현 클래스 계층 (Impl 계열)을 분리하여 연결 (bridging)하는 패턴이다.
- Template Method나 Strategy 패턴이랑 유사. 특히 Strategy 패턴과는 그림도 동일함. 다른 점은 분류상 Bridge는 구조에 관한 (Structural) 패턴이고 Strategy는 행위에 관한 (Behavioral) 패턴이라는 차이가 있다.
- 실제 클래스와 Impl 클래스를 분리하는데 이렇게 하면 실제 클래스의 기능 확장을 위해 상속을 사용할 수 있다. (요샌 이런 방식 잘 안하지만) 이렇게 상속 클래스를 그림에 끼워 넣으면 장점이 좀 더 잘 보인다.
- 여기서 Impl 클래스를 interface로 선언하여 ConcreteImplementation이 가능하게 하는 것은 구현 방법도 교체할 수 있게 하기 위함이다.
- Abstraction과 Implementor간의 연결이 위임이고 위임은 느슨한 연결이다. (둘간의 메소드 이름이 거의 유사)
- 전략을 사용하는 Context는 Strategy를 사용하는데 이때 위임의 방식을 사용한다. (동일한 method signature를 갖는 경우도 있다)
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Adapter
- Wrapper 패턴이라고도 함. 이미 제공되어 있는 것을 필요한 쪽이 쓸 수 있도록 해주는 것이 일.
- 상속을 이용할 수도 있고 위임을 이용할 수도 있다.
- 필요한 메소드를 정의한 Adapter interface가 있다. 보아하니 Adaptee라는 클래스가 그 기능을 대충 제공한다. 이때 ConcreteAdapter는 Adapter를 implements하고 Adaptee를 extends해서 만들어도 되고 그냥 Adapter만 implements하고 Adaptee는 위임으로 갖고 있어도 된다. (후자가 바람직)
- Proxy 패턴과 매우 유사한데, Proxy 패턴에서 위임 관계인 Proxy와 RealSubject간에 interface가 같은 반면 여기서 ConcreteAdapter와 Adaptee는 아무 관계가 없다. 그야말로 느슨하다.
- 소스가 있든 native library형태로만 제공되든 그걸 감싸는 wrapper class들은 Adapter 패턴이라고 보면 된다.
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Prototype
- 용어가 주는 느낌과 달리 deep copy를 지원하는 복사생성자 패턴이라고 보면된다. 마치 Java의 cloneable과 같다.
- Prototype (cloneable) interface를 구현하면 clone()을 제공해야 한다.
- Java cloneable은 메소드를 정의하고 있지는 않고 단지 표식일 뿐이다. 이것만 implement 선언하면 JVM이 알아서 clone 메소드를 지원해주고 만일 선언하지 않은 클래스의 clone 메소드를 호출한다면 CloneNotSupportedException이 발생한다.
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Builder
- 요즘 많이 쓰는 API의 Builder 패턴과는 조금 다르다. 그건 immutable instance를 만들기 위해서 인스턴스 생성전에 이것 저것 값을 채워넣는 방식이고 여기서의 Builder 패턴은 무언가를 만드는 과정을 명세하고 실제로 만드는 구현은 분리한 것이다.
- Abstract Factory와 Factory Method와도 비슷한데 차이점은 Factory Method는 단일 product 생성을 완전히 추상화 하였고 Abstract Factory는 부품을 명세하되 조립과정은 Client가 작성하는데 비해 Builder 패턴에서는 Builder interface에서 하나의 product를 만들기 위한 부분 제작 과정을 명세하였다는 점이다.
- ConcreteBuilder는 명세를 따르면 제품이 나오도록 구현되어야 한다. 대신 최종 product는 따로 class화 하지 않았는데 그냥 Director가 ConcreteBuilder의 getResult()를 직접 호출한다. 이 부분이 좀 이상하긴 한데 Director의 construct()를 호출할 때에도 ConcreteBuilder를 넣어주어야 하고 Director는 명세를 호출할 뿐이긴 하지만 최종 결과물에서는 ConcreteBuilder를 알아야한다는 점에서 Director에게 ConcreteBuilder를 hide하는 패턴은 아니다. 제작 과정만 놓고 본다면, 즉 construct() 내부 구현이 ConcreteBuilder 교체로 인해 바뀌지 않는다는 점은 있다.
이글은 책 "Java언어로 배우는 디자인 패턴 입문"을 읽고 쓴 요약입니다.
나만 이해하도록 불친절하게 작성되어 있습니다.
자세한 내용은 책을 보세요.
Abstract Factory
- Factory Method와 거의 유사한데 하나의 product에만 초점을 맞춘 것이 아니라 여러 product를 생성하고 이를 조합하는 과정에 초점이 맞춰져 있다.
- Client가 AbstractFactory보고 product A 내놔 B 내놔.. 해서 A계열의 AbstractProduct와 B 계열의 AbstractProduct를 얻어온다음 그걸로 뭔가 최종 제품을 만든다. 그래서 여기서의 AbstractProduct는 제품이라기 보다는 부품이라고 보는 것이 좋다.
- 그리고 이런 일련의 부품들을 제공하는 ConcreteFactory의 선정이 중요한데 그 부분까지 다룬다. 예제에서는 class이름을 command line 입력으로 받아서 ConcreteFactory를 만듦으로써 입력에 따라 전혀 다른 제품이 생성될 수 있도록 했다.
- 새로운 제품군을 위한 공장과 부품 추가는 쉬운 반면, 새로운 부품 유형을 추가하는 것은 어렵다. 즉, product C 추가는 어렵다.