디자인 패턴의 주요 관점:
1) 동일 코드 및 유사 코드까지 통합하려고 객체 지향의 다형성을 이용하여 코드 중복을 제거 하고
2) 객체 지향의 추상화 인터페이스 레벨을 맞추어 기존 코드를 수정하지 않고 새로운 코드를 추가하여 사용하도록 구성하는 방법 <-- 디자인 패턴의 첫번째 목적은 유지보수성(변경용이성), 두번째는 재사용(기존 패턴 방식의)
: 모양과 구성 방법이 같더라도 사용 목적에 따라 다르게 취급함. 예) Proxy pattern <-> Decorator Pattern
생성 | 구조 | 행동 | |
class 상속 | Factory Method | Adapter | Interpreter Template Method |
객체 동적 변경 | Abstract Factory Builder Prototype Singleton |
Adapter Bridge Composite Decorator Facade Flyweight Proxy |
Chain of Responsibility Command Iterator Madiator Memento Observer State Strategy Visitor |
각 디자인 패턴 설명
디자인 패턴 | 설명 | 다이어그램 |
Iterator | 자료 저장과 자료 순회 역할을 독립적으로 분리하여 동일한 인터페이스로 접근하여 순차 접근할 수 있도록 구성, 오른쪽 그림에서 MyArray와 MyList는 자료 저장 역할을 하고 있으며 Position이라는 통일된 인터페이스로 자료 순회 역할을 분리하여 상세 구현한다. (← 단일 책임 원칙) |
|
Composite | 관련된 객체들을 하나의 인터페이스로 다룰 수 있도록 일관성을 부여 (예: 파일과 디렉토리를 같은 인터페이스로 접근 가능) - 객체 컬랙션은 다시 다형성으로 상속하여 구현 할 수 있음: https://syseng.tistory.com/212 |
|
Command |
execute(), undo(), redo() 등의 명령을 처리하는 일관된 인터페이스를 상속하는 객체로 구현 | |
Command + Composite | 명령들의 묶음을 Composite 패턴을 활용하여 동일한 인터페이스로 처리: 오른쪽 MicroCommand class는 여러 명령들의 묶음을 가지는 Collection 객체 class |
|
Proxy | 다른 용도의 기능을 중간에 넣고 빼기 쉽게 하기 위해서 기존과 동일한 인터페이스를 상속하여 제공하고 기존 기능을 사용하기 위해서 다시 이 인터페이스를 통해서 기존 기능들로 재 구성(Composite 패턴과 유사) 할 수 있다. 오른쪽 그림 MySynchrozedList는 MyList 인터페이스를 통해서 기존 MyLinkedList class를 호출 함. |
|
Decorator |
상속없이 객체에 새로운 서비스를 추가하려는 목적, Composite 패턴으로 다형성을 구현하여 중간 삽입/삭제가 용이하도록 함, Decorator끼리 겹쳐서 여러 기능을 사용 가능 Proxy와 Decorator는 생김새가 동일한데 사용하는 목적이 다름 |
|
Adapter | 인터페이스가 다를 때 이를 일관된 인터페이스로 다시 제공하기 위해 해당 class를 일관된 인터페이스의 구현으로 감싸서 변환 | |
Observer |
객체들간 의존성을 최소화 하면서 여러 객체에 이벤트 전달, 구독자는 동적 증가/감소 가능, 상태가 변경되면 다른 객체들한테 연락 (상위 레이어로 callback 또는 listener에 사용: 역방향) 우측 그림에서 MyTextView(Observer)는 MyIntDocument(Subject)에 정보가 갱신되면 연락을 받는다. MyIntDocument::addObserver(MyTextView) 하면 내부적으로 MyView::update(Observable)가 호출됨. https://syseng.tistory.com/213 (1:N) Pub/Sub 패턴과 유사한 듯 하지만 차이점 : Observer는 Broker가 없음. Broker로 인해 Pub/Sub에서는 양쪽 모두 의존성이 없음. Observer는 동기, Pub/Sub은 비동기 |
|
Mediator | 관련된 객체 사이의 복잡한 제어를 Mediator에 집중 1) 초기화: Dialog는 ListBox, Button을 생성 후 Widget::setMediator(this)로 자신을 Mediator로 Widget에 등록함 2) 이벤트 호출: ListBox::widgetChanged() → Widget::widgetChanged() → FileOpenDialog::childChanged() 로 호출됨 Observer는 Subject에서 trigger하지만 Mediator는 각 Colleague가 trigger 함 |
|
Visitor | 데이터에 대한 멤버변수와 메소드를 분리하여 유지 보수 용이하게, 메소드를 별도의 Visitor 클래스로 분리하여 기능이 필요한 객체는 해당 Visitor 객체를 받아 드려서 수행. 우측 그림에서 Line::accept(VisitorSum) -> VisitorSum::visit(Line(this)) -> Line에서 정보 얻어서 VisitorSum 동작 수행, VisitorSum::visit()의 구현을 바꾸면 원하는 동작을 수정 가능 [문제점] Client에 각 구현 class 의존성 있음 |
|
Strategy | 여러 상황에 따라 구현이나 알고리즘을 변경하여 사용할 수 있도록 (동적 변경도 가능) 우측 그림에서 Context는 각 Strategy들을 교체하여 사용, Client에서 AlgorithmA/B에 대한 의존성을 Context로 이동 |
|
Template Method | 전체 구성은 같으나 몇몇 세부 동작이 다를 때 변경되는 단위스텝들을 abstract method로 선언 하여 상속된 객체에서 각각 다르게 구현 |
|
State | 상태를 기반으로 한 행동을 캡슐화한 다음 위임을 통해서 필요한 행동을 선택, switch/case 없이 구현, 상태 단위로 유지/보수가 이루어지기 때문에 상태 단위로 구현하는 것이 가독성과 유지/보수성이 좋다 : class 구성은 Strategy Pattern과 동일하나 캡슐화하는 내용과 목적이 다름 |
|
Bridge | 기능과 상세 구현의 분리 기능 - Printer::drawLine() 상세 구현 - PrinterDev::PrintCmd1(), PrinterDev::PrintCmd2() LajerPrinterDev가 추가될 경우 변경 사항은 LajerPrinterDev 추가와 의존성 주입만 수정 |
|
Chain of Responsibility (책임 연쇄) |
Chain 객체들을 대상으로 연쇄적으로 요청을 전달하여 처리 요청을 하는 쪽과 받는 쪽의 의존성이 낮다 요청을 받는 객체가 자유롭게 추가/제거 가능 Chain의 각 객체들은 RequestHandler::handleRequest()를 구현 Chain의 각 객체들은 RequestHandler 인터페이스의 객체로 요청 전달 |
|
Flyweight | 중복되는 객체를 공유하면서 메모리 사용량을 줄이기 위해 객체의 상태들을 Client에서 관리하고 중복되는 객체는 형태로만 유지 | |
Facade | 서브시스템에 대한 통합된 단순화된 인터페이스 제공 | |
생 성 |
||
Factory Method | Factory 인터페이스를 상속한 구현 클래스에서 필요한 객체 생성, 오른쪽 그림에서 ProductImplement에 대한 의존성을 Client에서 FactoryImplement로 이동 | |
Abstract Factory | 여러 객체를 의존적으로 다르게 생성하고자 할때 우측 그림에서 Client는 WinWidgetFactory와 MacWidgetFactory만 알고 있고 각 Botton과 TextBox는 WidgetFactory가 알아서 생성함 Botton과 TextBox 생성 의존성을 WidgetFactory를 상속하는 객체로 이동 |
|
Builder | 여러 단계와 다양한 절차를 통해서 객체를 생성 (Factory는 한 단계에서만 생성), 반면 Client는 객체 생성에 대한 정보를 더 많이 알아야 함. 우측그림에서 CsvBuilder와 HtmlBuilder는 MyBuilder 인터페이스를 상속하여 구현했으므로 buildTable()에서 MyBuilder 인터페이스를 이용하여 동작 함. 여러 ConcreteBuilder 중에 하나를 사용하는 것은 Strategy pattern과 유사한 구조로 볼 수 있음. |
|
Prototype | class name을 명시하지 않고 일관된 인터페이스로 객체를 새롭게 생성할 수 있는가? 생성 시 객체 복사 (deep copy) 필요 |
|
Singleton | multi thread에 안전한 단일 인스턴스 생성 | |
Memento | 객체의 중요한 상태를 따로 저장하는 역할의 Memento 객체로 이전 상태 복원 |
모양이 유사한 디자인 패턴들
디자인 패턴 이름 | 다이어그램 | 차이점 |
Proxy Adapter |
Proxy: 중간에 추가 되거나 수정 되는 기능들을 동일 인터페이스에서 대응하기 위해 Adapter: 가져온 라이브러리 인터페이스가 제공 해야 할 인터페이스와 서로 다를 때 |
|
Composite Proxy Decorator |
Composite: 여러 객체 및 객체 컬랙션을 단일 인터페이스로 관리하기 위해 Proxy: 중간에 추가 되거나 수정 되는 기능들을 동일 인터페이스에서 대응하기 위해 Decorator: 상속없이 객체에 새로운 기능들을 추가하기 위해 |
|
Adapter Facade Bridge |
Adapter: 서로 다른 인터페이스를 동일하게 맞춤 Facade: 복잡한 내부 내용을 단순한 인터페이스로 제공 Bridge: 기능 정의와 실제 상세 구현을 분리 하기 위해 |
|
Observer Mediator |
다이어그램은 서로 다름 개념이 상반됨 |
Observer: 단일 지점의 변경 내용을 여러 Subscriber들에게 연락 Mediator: 여러 하위 모듈들의 변경 내용을 Mediator로 모아서 처리 후 하위 모듈로 재 분배 |
Strategy Template Method |
구현하는 방식이 메소드 호출과 상속으로 차이 | 여러 상황에 따라 구현이나 알고리즘을 변경 Strategy: 동일 인터페이스에 다른 동작 구현 Template Method: 다른 동작 구현을 상속을 통하여 다형적으로 구현 |
Strategy State Builder |
Strategy: 동일 인터페이스에 다른 동작 구현을 캡슐화 State: 상태에 따른 행동을 캡슐화 Builder: 객체를 생성하는 해동을 캡슐화 |
참고한 블로그:
https://sncap.tistory.com/1093
https://johngrib.github.io/wiki/pattern/
https://gmlwjd9405.github.io/tags#%EB%94%94%EC%9E%90%EC%9D%B8%ED%8C%A8%ED%84%B4
https://lktprogrammer.tistory.com/category/Study/%EB%94%94%EC%9E%90%EC%9D%B8%20%ED%8C%A8%ED%84%B4
'architecture' 카테고리의 다른 글
observer design pattern example (0) | 2022.11.29 |
---|---|
composite design pattern example (0) | 2022.11.29 |
[My cheat-sheet] PUML (0) | 2021.09.29 |
댓글