Skip to main content

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);
    }
}
  • 사용 사례: 복잡한 객체 구조에서의 연산
  • 장점: 새로운 연산 추가 용이
  • 단점: 요소 클래스 수정 필요