Design Pattern
- Design Pattern이란?
- A Solution to a problem in a context
- OOAD에서 자주 발생하는 문제에 대한 재사용 가능한 해결책
- Design Pattern의 장점?
- 코드의 재사용성이 좋아진다
- 의사소통의 도구이다
- 설계에 대한 이해가 쉽다
Design Pattern의 종류
목적에 따른 Design Pattern
Creational Design Pattern
- 객체 인스턴스 생성을 위한 패턴으로, Client와 Concreate Instance와의 decoupling을 하게 해주는 패턴들이다. => new 키워드 없이 생성
- 종류 : Singleton, Factory Method, Abstract Factory, Builder, Prototype
Structural Design Pattern
- 프로그램 또는 데이터 구조와 관련된 패턴으로, 클래스와 composition을 통해서 큰 구조로 만들 수 있게 해주는 것과 관련된 패턴
- 종류 : Composite, Bridge, Adaptor, Decorator, Proxy, Flyweight, Facade
Behavior Design Pattern
- 클래스와 객체들이 상호작용하는 방법 및 역할을 분담하는 방법과 관련된 패턴
- 종류 : Interpreter Pattern, Templete Method, Chain of Responsibility, Command, Iterator, Mediatro, Memento, Observer, State, Strategy, Visitor
범위에 따른 Design Pattern
- 클래스 패턴 : 클래스 사이가 상속을 통해서 정의된다. 클래스 패턴은 컴파일 시에 관계가 정의 됨
- 객체 패턴 : 객체 사이의 관계를 다루며, 객체 사이의 관계는 보통 구성을 통해서 정의 된다. Runtime 시에 관계가 생성되기 때문에 더 동적이고 유연하다
Creational Design Pattern
Singleton
- 정의 : 단 한개의 인스턴스를 보장해주는 패턴
- 상황 : 단 한개의 인스턴스가 필요할 때 사용
- 장점 : 단 한개의 인스턴스가 보장 된다
- 단점
- 객체 지향 개념에 맞지 않는다
- 전역변수와 같이 사용되어 어디서든 접근 가능하기 때문에 dependency, 복잡도가 증가한다.
- 서버와 같은 환경에서는 단 한개가 보장되지 않을 수 있다.
Factory Method Pattern
- 정의 : 생성에 대한 인터페이스를 정의 하지만, 인스턴스를 만드는 클래스는 서브 클래스에게 위임하는 패턴
- 상황 : 동일 생성에 대한 인터페이스가 필요한데, 상세 인스턴스는 다르고 이를 캡슐화하고 싶은 경우
- ex) Tea 생성 Coffee 생성 물끓이고 하는건 비슷
- 장점
- 새로운 객체 생성 시, 기존의 코드 변경 없이 추가가 편하다.
- 단점
- 불필요하게 많은 클래스를 정의 하여 복잡해질 수 있음
Abstract Factory Pattern
- 정의 : family of product의 동일 인터페이스를 제공하여 상세 생성의 책임은 서브 클래스에게 위임하는 패턴
- 상황 : family of product을 생성하려고 할때
- ex) UI의 테마 변경
- 장점
- 제품군의 증가가 쉽다. OCP
- 단점
- 제품군 내의 제품이 추가 (인터페이스 변경)이 되는 경우 대규모 수정이 필요하다.
Builder Pattern
- 정의 : 객체 생성의 알고리즘과 상세 구현 방법을 나누어 생성하는 패턴. 주로 매우 복잡하고 큰 객체를 생성할때 사용
- 상황 : 객체 생성이 매우 복잡한 여러 종류의 객체를 생성할때 사용
- ex) 비행기 제품군처럼 부품이 많고 다양한 객체
- 장점
- Client와 복잡한 생성을 분리하여 decoupling
- 제품 확장에 좋다 OCP
- 단점
- 전체적인 코드의 복잡도는 늘어날 수 있음
Prototype Pattern
- 정의 : 객체의 복사해 인스턴스를 만드는 패턴
- 상황 : 객체의 복사가 잦은 경우 사용
- ex) clone 메소드
- 장점
- 객체의 복사를 정의하기 때문에 중복 코드를 줄일 수 있다
- 단점
- 순환 참조가 있는 복잡한 객체를 복제하는 것은 매우 까다로울 수 있음
Structural Pattern
Adaptor Pattern
- 정의 : 미리 구현된 서로 다른 인터페이스를 맞춰주는 패턴
- 상황 : 미리 구현된 서로 다른 인터페이스를 맞춰줄때 사용
- ex) Java- > itorator, enumerator
- 장점
- 미리 구현된 코드를 재사용 가능하게 해주기 때문에 재사용성이 증가한다
- 단점
- 복잡도가 증가됨
Composite Pattern
- 정의 : 계층 구조를 상속과 Composite을 이용하여 구현하는 패턴
- 상황 : 계층 구조를 구현하려고 할때 사용
- 장점 :
- 계층 구조를 구현할때 용이
- 계층 구조간 확장이 용이 하다 OCP
- 단점 :
- 클래스간 기능이 서로 다르기 때문에 interface가 완전히 동일하기 어려움
Decorator Pattern
- 정의 : 상속과 Composition을 이용하여 동적으로 책임을 부여해주는 패턴. 서브클래싱을 이용한 확장이 비효울적일때 효율적으로 책임을 추가하기 좋다.
- 상황 : 동적으로 책임을 부여하고 싶을때, 서브클래싱으로 책임 추가가 비효율 적일때
- ex) 커피, 디카페인, 휘핑, 샷 추가 등
- 장점 :
- 동적으로 책임을 추가 할 수 있다
- 신규 기능 추가가 쉽다(OCP)
- 단점 :
- 코드가 복잡해 질수 있다
Proxy Pattern
- 정의 : Object Level의 접근하는 것을 통제 하기 위해서 그 객체의 대리자 또는 placeholder를 제공하는 패턴
- 상황 : 접근을 통제 하여 대리자가 대체 할때 효율적인 경우
- Remote Proxy : 네트웍 상의 객체를 local인것 처럼 행동하게 한다
- Virtual Proxy : 생성시 많은 비용이 드는 경우 생성이 완료 시 까지 대체 한다
- Protection proxy : 접속의 제한이나 데이터 변경의 제한 필요한 경우 접근을 제어 한다.
- 장점:
- caller와 callee간의 decoupling으로 인한 callee의 변경에도 caller는 영향을 받지 않음
- callee의 identity를 감출 수 있다
- 단점:
- 인터페이스 증가에 따른 오버헤드 증가
Flyweight
- 정의 : 동일하게 사용될 수 있는 메모리를 공유 하여 낭비를 없애는 패턴
- 상황 : 인스턴스가 자주 생성되는데, 생성시 리소스 낭비가 심하고 공유가 가능할때
- ex) Big Charactor 출력
- 장점 : 메모리를 공유 하기 때문에 메모리를 효율적으로 사용 가능하다. 이에 따른 퍼포먼스 향상
- 단점 :
- factory에서 관리하는 메모리는 가비지 컬렉터에 의해 컬렉팅 되지 않기 때문에 리소스 낭비가 심할 수 있다
- 구현이 복잡하다
Facade
- 정의 : client와 implemetation간의 간단한 인터페이스 제공하는 패턴. 복잡한 인터페이스를 간단하게 해준다.
- 상황 : Client와 implentation간의 복잡한 인터페스가 있는 경우
- 장점 :
- 인터페이스를 간단하게 해준다
- Client와 subsystem간의 coupling을 약하게 해준다
- 단점 :
- 직접적으로 연결을 막을 수 없다. package화 필요.
Bridge
- 정의 : 추상과 구현을 분리시켜 각자 독립적으로 변형할 수 있게 하는 패턴.
- 상황 : 추상과 구현이 각자 독립적으로 확장되어야 할 때 사용.
- 장점
- OCP를 잘 준수 하기 때문에 추상과 구현이 독립적으로 확장이 가능하다.
- 단점
- 구현이 조금 복잡하다
Behavioral Pattern
Stategy Pattern
- 정의 : 동일한 인터페이스의 알고리즘을 런타임에 동적으로 변경가능하도록 제공해주는 패턴
- 상황 : Runtime에 동적으로 알고리즘의 변경이 필요한 경우
- 장점
- 알고리즘의 확장이 좋다 OCP
- 동적으로 알고리즘 변경이 가능하기 때문에 유연하다
- 단점
- 간단한 알고리즘의 경우 직접 구현하는게 좋다
- 오버헤드가 증가한다
Interpreter Pattern
- 정의 : 프로그래밍 언어를 구현해주는 패턴
Templete Method
- 정의 : 알고리즘의 Skeleton을 정의하고 각 단계의 구체적인 처리는 서브 클래스에게 위힘하는 패턴.
- 상황 : 하위 클래스가 공통적인 알고리즘 구조가 필요한 경우
- ex) JFrame
- 장점 :
- 상위 클래스로부터 공통 알고리즘을 사용 가능하다. 중복 코드를 제거 가능.
- 단점 : 추상 메소드가 많아지면서 클래스 관리가 복잡해져 유지보수가 어려울 수 있다.
Chain of Responsibility
- 정의 : 요청 처리를 하나 이상의 객체에 부여하여 요청자와 요청을 받는 객체간의 결합을 피하는 패턴
- 상황 : 사전에 어떤 요청을 어떤 객체가 해결해야할지 모르는 경우
- ex) UI 이베트 처리
- 장점 :
- 요청자와 요청을 수행하는 객체간의 decoupling
- 요청자는 누가 요청을 수행해야 하는 지식이 필요없다
- 단점 :
- 요청 수행의 퍼포먼스 저하
- 요청 수행이 100% 된다는 보장이 없다
Command
- 정의 : 명령 수행에 대한것을 동일한 interface로 객체화하여 제공하는 패턴. invoker와 reciever간의 decoupling
- 상황 :
- 동일한 형태의 명령 수행이 필요한경우.
- 명령 수행에 대한 로그를 남겨야 하는 경우Chain of Responsibility
- 장점 :
- invoker와 reciever간의 decoupling
- 새로운 명령어를 추가 하기 쉽다. OCP
- 단점 :
- 클래스 갯수의 증가
- overhead 증가
Iterator
- 정의 : 내부 구성 요소의 디테일은 감추고, 순회를 가능하게 하는 패턴
- 상황 : 서로 다른 내부 구성요소를 감추고 동일한 인터페이스로 순회를 하려고 할때 사용
- 장점
- SRP,OCP. 순회에 대한 책임, 구성 요소 구현에 대한 책임을 잘 나누어져, 확장에 좋다
- 단점
- 클래스의 증가. 단순한 컬렉션의 경우 과도할 수 있음
- 단순한경우 직접 구현하는게 속도가 더 빠르다
Mediator
- 정의 : collegue끼리 복잡한 커플링을 mediator, 즉 중재자 역활을 하는 객체를 둠으로써, 복잡한 커플링을 줄여주는 패턴
- 상황 : collegue끼리 복잡한 커플링이 발생하는 경우. 중재자가 필요한 경우
- 장점
- collegue끼리의 복잡한 커플링을 줄여준다
- SRP. collegue의 본인의 역할에 집중 할 수 있다
- 단점
- 중재자는 재사용이 거의 불가능하고, 복잡도가 증가한다
Memento
- 정의 : 현재 상태를 저장하고 복구하는 기능을 제공하는 패턴
- 상황 : 현재 상태를 저장하거나 복구 하고 싶을 때
- Caretaker는 저장과 복구 시점을 컨트롤
- Originator는 실제 저장과 복구를
- 장점
- 현재 상태를 저장할 수 있다
- Caretaker는 Memento의 상세 구조를 알 필요 없다. 디커플링
- 단점
- 많은 빈도수의 저장은 메모리 낭비를 야기시킨다
Observer
- 정의 : 1 to many 의존관계에서 이벤트 송수신을 제공하는 패턴.
- 상황 : 의존관계에서 이벤트 송수신이 필요한경우.
- 장점
- Observer와 Subject간의 coupling을 최소화한다
- OCP. Ovserver와 Subject의 확장이 쉽다
- 단점
- 송수신의 순서를 보장해주지 못 한다
State
- 정의 : state 머신을 구현을 해주는 패턴. 객체들은 state 상태에 따라 다른 행동을 한다.
- 상황 : state 머신을 구현해야 할때. state에 따른 객체의 행위를 변경해야 할때 사용
- 장점
- OCP. Switch문 제거가 가능하며, 새로은 상태 정의 즉, 확장이 쉽다
- 단점
- 클래스의 증가
- interface가 변경되는경우. 대규모 수정이 요구된다.
Visitor
- 정의 : 요소를 순회하면서 특별한 연산과 같은 행동을 해야 할때 사용하는 패턴
- 상황 : 요소를 순회하면서 특별한 연산이 필요한 경우
- 순회 -> accpet -> visit -> 반복
- 장점
- 요소와 행위(연산)을 분리시켜 확장이 쉽다.
- 단점
- 요소의 내부구조의 확장이 어렵다