GoF (Gang of Four) 디자인 패턴
작성일 : 2025.01.07
1. 생성 패턴 (Creational Patterns)
1.1 싱글톤 패턴 (Singleton)
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
- 사용 사례: 데이터베이스 연결 관리, 로깅, 환경설정 등
- 장점: 리소스 절약, 전역 상태 관리 용이
- 단점: 단위 테스트 어려움, 전역 상태로 인한 복잡성
1.2 추상 팩토리 패턴 (Abstract Factory)
public interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
public class WindowsFactory implements GUIFactory {
public Button createButton() { return new WindowsButton(); }
public Checkbox createCheckbox() { return new WindowsCheckbox(); }
}
public class MacFactory implements GUIFactory {
public Button createButton() { return new MacButton(); }
public Checkbox createCheckbox() { return new MacCheckbox(); }
}
- 사용 사례: 크로스 플랫폼 UI 컴포넌트, DB 연결 관리자
- 장점: 제품군 일관성 보장, 구체적 클래스 분리
- 단점: 새로운 제품 추가 시 인터페이스 수정 필요
1.3 빌더 패턴 (Builder)
public class Computer {
private String CPU;
private String RAM;
private String storage;
public static class Builder {
private Computer computer = new Computer();
public Builder CPU(String cpu) {
computer.CPU = cpu;
return this;
}
public Builder RAM(String ram) {
computer.RAM = ram;
return this;
}
public Builder storage(String storage) {
computer.storage = storage;
return this;
}
public Computer build() {
return computer;
}
}
}
- 사용 사례: 복잡한 객체의 단계별 생성
- 장점: 객체 생성 과정의 유연한 변경 가능
- 단점: 코드 복잡성 증가
1.4 프로토타입 패턴 (Prototype)
public interface Cloneable {
Cloneable clone();
}
public class ConcretePrototype implements Cloneable {
private String field;
public Cloneable clone() {
ConcretePrototype clone = new ConcretePrototype();
clone.field = this.field;
return clone;
}
}
- 사용 사례: 객체 복사가 생성보다 효율적일 때
- 장점: 복잡한 객체 생성 비용 감소
- 단점: 순환 참조 처리 필요
1.5 팩토리 메서드 패턴 (Factory Method)
public abstract class Creator {
abstract Product factoryMethod();
public void anOperation() {
Product product = factoryMethod();
product.operation();
}
}
public class ConcreteCreator extends Creator {
public Product factoryMethod() {
return new ConcreteProduct();
}
}
- 사용 사례: 프레임워크에서의 객체 생성
- 장점: 객체 생성의 유연성 제공
- 단점: 클래스 수 증가
2. 구조 패턴 (Structural Patterns)
2.1 어댑터 패턴 (Adapter)
public interface Target {
void request();
}
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
public void request() {
adaptee.specificRequest();
}
}
- 사용 사례: 외부 라이브러리 통합, 레거시 시스템 연동
- 장점: 호환성 문제 해결
- 단점: 추가 코드 작성 필요
2.2 브리지 패턴 (Bridge)
public abstract class Abstraction {
protected Implementor implementor;
public Abstraction(Implementor implementor) {
this.implementor = implementor;
}
abstract public void operation();
}
public interface Implementor {
void operationImpl();
}
- 사용 사례: 플랫폼 독립적인 GUI
- 장점: 추상화와 구현의 분리
- 단점: 복잡성 증가
2.3 컴포지트 패턴 (Composite)
public abstract class Component {
protected String name;
public Component(String name) {
this.name = name;
}
abstract public void operation();
}
public class Composite extends Component {
private List<Component> children = new ArrayList<>();
public void add(Component component) {
children.add(component);
}
public void operation() {
for (Component child : children) {
child.operation();
}
}
}
- 사용 사례: 파일 시스템, GUI 컴포넌트
- 장점: 복잡한 트리 구조 단순화
- 단점: 설계의 일반화로 제약사항 설정 어려움
2.4 데코레이터 패턴 (Decorator)
public abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
public void operation() {
component.operation();
}
}
- 사용 사례: I/O 스트림, UI 컴포넌트 기능 확장
- 장점: 동적인 기능 추가 가능
- 단점: 작은 객체가 많이 생성될 수 있음
2.5 퍼사드 패턴 (Facade)
public class Facade {
private SubsystemA subsystemA;
private SubsystemB subsystemB;
public Facade() {
subsystemA = new SubsystemA();
subsystemB = new SubsystemB();
}
public void operation() {
subsystemA.operationA();
subsystemB.operationB();
}
}
- 사용 사례: 복잡한 서브시스템 단순화
- 장점: 시스템 복잡도 감소
- 단점: 퍼사드가 병목점이 될 수 있음
3. 행위 패턴 (Behavioral Patterns)
3.1 책임 연쇄 패턴 (Chain of Responsibility)
public abstract class Handler {
protected Handler successor;
public void setSuccessor(Handler successor) {
this.successor = successor;
}
public abstract void handleRequest(Request request);
}
- 사용 사례: 이벤트 처리, 로깅 시스템
- 장점: 요청 처리의 유연성 증가
- 단점: 처리 경로 추적 어려움
3.2 커맨드 패턴 (Command)
public interface Command {
void execute();
}
public class ConcreteCommand implements Command {
private Receiver receiver;
public void execute() {
receiver.action();
}
}
- 사용 사례: 작업 큐, 트랜잭션
- 장점: 작업의 캡슐화, Undo/Redo 구현 용이
- 단점: 명령당 클래스 필요
3.3 인터프리터 패턴 (Interpreter)
public interface Expression {
boolean interpret(String context);
}
public class TerminalExpression implements Expression {
private String data;
public boolean interpret(String context) {
return context.contains(data);
}
}
- 사용 사례: 파서, 수식 계산기
- 장점: 문법 규칙 추가/수정 용이
- 단점: 복잡한 문법에서 클래스 증가
3.4 반복자 패턴 (Iterator)
public interface Iterator {
boolean hasNext();
Object next();
}
public class ConcreteIterator implements Iterator {
private List<Object> list;
private int index;
public boolean hasNext() {
return index < list.size();
}
public Object next() {
if (hasNext()) {
return list.get(index++);
}
return null;
}
}
- 사용 사례: 컬렉션 순회
- 장점: 일관된 순회 방법 제공
- 단점: 간단한 순회에도 클래스 필요
3.5 중재자 패턴 (Mediator)
public interface Mediator {
void notify(Component sender, String event);
}
public class ConcreteMediator implements Mediator {
private Component1 component1;
private Component2 component2;
public void notify(Component sender, String event) {
if (sender == component1) {
component2.receive(event);
} else {
component1.receive(event);
}
}
}
- 사용 사례: GUI 컴포넌트 간 통신
- 장점: 컴포넌트 간 결합도 감소
- 단점: 중재자 복잡도 증가
3.6 메멘토 패턴 (Memento)
public class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
public class Originator {
private String state;
public Memento saveToMemento() {
return new Memento(state);
}
public void restoreFromMemento(Memento memento) {
state = memento.getState();
}
}
- 사용 사례: 실행 취소 기능
- 장점: 상태 저장과 복원 용이
- 단점: 메모리 사용량 증가
3.7 옵저버 패턴 (Observer)
- 앞서 설명드린 내용과 동일
3.8 상태 패턴 (State)
public interface State {
void handle(Context context);
}
public class Context {
private State state;
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle(this);
}
}
- 사용 사례: 워크플로우 관리
- 장점: 상태 전이 명확화
- 단점: 상태 클래스 수 증가
3.9 전략 패턴 (Strategy)
public interface Strategy {
void execute();
}
public class Context {
private Strategy strategy;
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void executeStrategy() {
strategy.execute();
}
}
- 사용 사례: 알고리즘 선택/교체
- 장점: 알고리즘 교체 용이
- 단점: 클라이언트가 전략을 알아야 함
3.10 템플릿 메서드 패턴 (Template Method)
public abstract class AbstractClass {
public final void templateMethod() {
operation1();
operation2();
hook();
}
abstract void operation1();
abstract void operation2();
void hook() {} // 선택적 오버라이드
}
- 사용 사례: 프레임워 크 개발
- 장점: 코드 재사용성 증가
- 단점: 상속을 통한 기능 확장
3.11 방문자 패턴 (Visitor)
public interface Visitor {
void visit(ElementA element);
void visit(ElementB element);
}
public interface Element {
void accept(Visitor visitor);
}
public class ConcreteElement implements Element {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
- 사용 사례: 복잡한 객체 구조에서의 연산
- 장점: 새로운 연산 추가 용이
- 단점: 요소 클래스 수정 필요