GoF(Gang of Four)에서는 23가지 디자인 패턴을 3가지 유형으로 분류합니다.
A. Creational Pattern
- 객체를 생성하는데 관련된 패턴들
- 객체가 생성되는 과정의 유연성을 높이고 코드의 유지를 쉽게 함
B. Structural Pattern
- 프로그램 구조에 관련된 패턴들
- 프로그램 내의 자료구조나 인터페이스 구조 등 프로그램의 구조를 설계하는데 활용할 수 있는 패턴들
C. Behavioral Pattern
- 반복적으로 사용되는 객체들의 상호작용을 패턴화 해놓은 것들
주요 디자인 패턴만 정리했습니다.
1. 어댑터 패턴(Adapter Pattern)
- 용도
- 어떤 클래스를 우리가 바로 사용할 수 없을 때가 있다. 다른 곳에서 개발한 클래스고, 우리가 그것을 수정할 수 없을 때, 우리에게 맞게 중간에 변환할 역할을 해줄 수 있는 클래스가 필요한데, 그것이 바로 어댑터이다.
- 사용 방법
- 상속
- 위임: 어떤 메소드의 실제 처리를 다른 인스턴스의 메소드에게 맡기는 방법
- Class Diagram
2. 프로토 타입 패턴(Prototype Pattern)
- 용도
- 미리 만들어진 객체를 복사해서 객체를 생성하는 방식
- 객체를 많이 만들어야 할 경우, 객체 생성에 드는 코딩 분량을 현저히 줄일 수 있다
- 클래스로부터 객체를 생성하기 어려운 경우(그래픽 에디터에서 사용자의 마우스 클릭으로 생성되는 객체들)
- 사용 방법
- 모형(Prototype) 인스턴스를 등록해 놓고, 등록된 인스턴스를 복사(clone())해서 인스턴스를 생성함
- Class Diagram
3. 싱글톤 패턴(Singleton Pattern)
- 용도
- 시스템 내부에 1개의 인스턴스만 생성하고 싶은 경우
- 컴퓨터 자체를 표현한 클래스
- 현재 시스템 설정을 표현한 클래스
- 시스템 내부에 1개의 인스턴스만 생성하고 싶은 경우
- 사용 방법
- 생성자를 private으로 선언하고, 해당하는 생성자를 클래스 내부에서만 호출함
- Class Diagram
4. 컴포지트 패턴(Composite Pattern)
- 용도
- 틀과 내용물을 같은 것으로 취급하고 싶을 때(디렉토리 내부에는 디렉토리와 파일이 있지만, 둘 모두 디렉토리 내부에 있는 Element로 표현하고 싶을 때)
- 사용 방법
- Composite클래스가 Component를 포함하도록 함
- Class Diagram // Composite이 Component를 포함하고 있음
5. 데코레이터 패턴(Decorator Pattern)
- 용도
- 데코레이팅한 결과물을 다시 내용물로 보고 그것을 다시 데코레이팅하기 위함(지속적으로 장식을 추가할 때, 문자열 주위에 여러 유형의 border 장식을 추가할 때)
- 사용 방법
- Border 클래스가 다시 Display를 포함함(컴포지트랑 비슷)
- Class Diagram // Decorator가 Component를 포함하고 있음
6. 퍼사드 패턴(Facade Pattern)
- 용도
- 대규모 프로그램에는 서로 관련있는 클래스들이 많음 -> 복잡하게 얽혀있는 클래스들을 정리해서 높은 레벨의 인터페이스(API)를 제공(간단하게 접근가능)
- 여러 클래스들을 직접 제어하지 않고 ‘창구(facade)’에 요구함
- 결과적으로 구현시에 간단한 인터페이스를 사용할 수 있게
- 사용 방법
- 여러 클래스들의 기능들을 묶은 Facade 클래스를 만들고 Facade 클래스에 접근함
- Class Diagram
7. 프록시 패턴(Proxy Pattern)
- 용도
- Proxy는 대리인이라는 의미, 시간이 많이 걸리는 작업을 할 때 사용함
- 시간이 많이 걸리는 작업을 할 때, 대리인이 할 수 있는 일은 대리인이 하고 할 수 없는 일(Heavy job)은 본래의 클래스에게 넘겨줌
- 시스템 초기화는 필요하지 않은 기능까지 초기화하려고 하면 많은 시간이 필요한데, 그 기능을 Proxy에 위임함
- 프린트 프로그램에서 실제 프린터를 실행하는 과정에 시간이 오래 걸리기 때문에 그 과정에 있는 일들을 Proxy에 위임함
- 사용 방법
- Proxy클래스에 우선 일을 위임하고, 그 뒤에 RealSubject가 해야할 일은 넘겨주는 방법으로 사용
- Class Diagram
8. 옵저버 패턴(Observer Pattern)
- 용도
- 관찰 대상의 상태가 변화했을 때 관찰자에게 통지하는 패턴
- 상태 변화에 따른 처리를 기술할 때 효과적으로 활용(MVC패턴에서 Model과 View의 분리 등)
- 사용 방법
- Observer 클래스에 상태 변화를 알려주고, Observer는 다시 그 변화에 맞는 결과를 나타냄
-
Class Diagram
-
구현 및 Code
- Observer Class
public interface Observer {
public abstract void update(NumberGenerator generator);
}
- NumberGenerator
import java.util.Vector;
import java.util.Iterator;
public abstract class NumberGenerator {
private Vector observers = new Vector(); // Observer들을 보관
public void addObserver(Observer observer) { // Observer를 추가
observers.add(observer);
}
public void deleteObserver(Observer observer) { // Observer를 삭제
observers.remove(observer);
}
public void notifyObservers() { // Observer에 통지
Iterator it = observers.iterator();
while (it.hasNext()) {
Observer o = (Observer) it.next();
o.update(this);
}
}
public abstract int getNumber(); // 수를 취득한다.
public abstract void execute(); // 수를 생성한다.
}
- RandomNumberGenerator
import java.util.Random;
public class RandomNumberGenerator extends NumberGenerator {
private Random random = new Random(); // 난수발생기
private int number; // 현재의 수
public int getNumber() { // 수를 취득한다.
return number;
}
public void execute() {
for (int i = 0; i < 20; i++) {
number = random.nextInt(50);
notifyObservers();
}
}
}
- DigitObserver
public class DigitObserver implements Observer {
public void update(NumberGenerator generator) {
System.out.println("DigitObserver:" + generator.getNumber());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
- GraphObserver
public class GraphObserver implements Observer {
public void update(NumberGenerator generator) {
System.out.print("GraphObserver:");
int count = generator.getNumber();
for (int i = 0; i < count; i++) {
System.out.print("*");
}
System.out.println("");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
- Main
public class Main {
public static void main(String[] args) {
NumberGenerator generator = new RandomNumberGenerator();
Observer observer1 = new DigitObserver();
Observer observer2 = new GraphObserver();
generator.addObserver(observer1);
generator.addObserver(observer2);
generator.execute();
}
}
9. 커맨드 패턴(Proxy Pattern)
- 용도
- 실행하고 싶은 메소드의 History 관리(우리가 Ctrl + z를 눌러서 실행취소를 한다고 할 때, History를 저장할 수 있어야 가능함)
- 매크로 명령을 정의하고자 할 때
- 동일한 명령을 반복해서 실행할 때
- 사용 방법
- 명령어를 객체에 캡슐화해 저장함(주로 스택으로 저장)
- Class Diagram
10. 책임 연쇄 패턴(Chain of Responsibility Pattern)
- 용도
- 어떤 요구가 발생했을 때, 그 요구를 처리할 Object를 바로 결정할 수 없을 때, 다수의 Object를 Chain으로 연결해 차례로 방문하면서 목적에 맞는 Object를 결정함(내가 못하면 남한테 전가시킴)
- 요구하는 측과 처리하는 측의 연결을 약화시킴(Coupling을 낮추는 역할을 함)
- 사용 방법
- Handler객체가 문제를 해결했는지 확인하면서 계속해서 가능한 객체를 연결해 줌
- Class Diagram
11. 중재자 패턴(Mediator Pattern)
- 용도
- 모든 행동을 수행하기 전에 ‘중재자 객체’의 결정이 있어야 하고, 중재자 객체로 프로그램이 수행됨
- 각 객체들은 중재자만 알게됨
- 사용 방법
- 각 객체와 중재자를 연결함
- Class Diagram
12. 방문자 패턴(Visitor Pattern)
- 용도
- 데이터와 메소드를 구분하기 위함
- 많은 데이터에 여러 가지 유형의 처리를 수행할 경우 활용
- 사용 방법
- 데이터 구조 내부를 traversal하는 ‘visitor’ 클래스로 그 클래스에게 데이터의 처리를 맡김, 새로운 처리를 추가할 때는 새로운 visitor를 생성함
- Class Diagram
13. 팩토리 메소드 패턴(Factory Method Pattern)
- 용도
- Instnce 작성을 하위 class에게 위임
- Instance를 만드는 방법은 상위 class에서 결정하지만, 구체적인 class명을 결정하지 않음
- Instance 생성을 위한 Framework과 실제 Instance를 생성하는 Class를 분리함
- 객체를 만드는 공장을 만드는 패턴 -> 결합도가 낮아질 수 있다
- Instnce 작성을 하위 class에게 위임
- 사용 방법
- Factory객체를 만들고 Factory에서 객체들을 생성한다
- Class Diagram