객체지향의 꽃, 디자인 패턴(Design Pattern) 핵심 요약

GoF(Gang of Four)가 정리한 23가지 패턴

2026.03.30

ProgrammingDesign_Pattern

디자인패턴 종류

  • 디자인 패턴(Design Pattern)은 소프트웨어 개발 중 반복적으로 발생하는 문제들에 대한 검증된 해결책 모음
  • GoF(Gang of Four)가 정리한 23가지 패턴이 가장 널리 알려져 있습니다.
  • 이 패턴들은 크게 생성, 구조, 행위 3가지 범주로 분류됩니다.

생성 패턴 (Creational) — 5가지

객체의 생성 방식을 결정하는 패턴입니다.

#패턴설명
1Singleton (싱글톤)클래스 인스턴스를 딱 하나만 생성하고 전역 접근점 제공
2Factory Method (팩토리 메서드)상위 클래스에서 인터페이스 정의, 하위 클래스에서 인스턴스 생성
3Abstract Factory (추상 팩토리)관련된 객체들의 집합을 생성하는 인터페이스 제공
4Builder (빌더)복잡한 객체의 생성 과정을 단계별로 분리해 단순화
5Prototype (프로토타입)기존 객체를 복사해 새로운 객체를 생성

구조 패턴 (Structural) — 7가지

클래스나 객체를 조합해 더 큰 구조를 만드는 패턴입니다.

#패턴설명
6Adapter (어댑터)호환되지 않는 인터페이스를 변환해 함께 동작하도록 연결
7Bridge (브리지)구현부와 추상층을 분리해 독립적으로 확장 가능하게 함
8Composite (컴포지트)개별 객체와 복합 객체를 동일하게 다루어 트리 구조 구성
9Decorator (데코레이터)객체에 동적으로 새로운 기능을 추가해 확장
10Facade (퍼사드)복잡한 서브시스템을 단순한 인터페이스로 감싸 쉽게 사용
11Flyweight (플라이웨이트)공유 가능한 객체를 통해 메모리 사용 최적화
12Proxy (프록시)다른 객체의 대리자를 제공해 접근 제어 및 지연 로딩 구현

행위 패턴 (Behavioral) — 11가지

객체나 클래스 사이의 알고리즘 및 책임 분배에 관련된 패턴입니다.

#패턴설명
13Observer (옵저버)한 객체의 상태 변화 시 의존 객체들에게 자동으로 알림 전달
14Strategy (전략)알고리즘을 캡슐화해 동적으로 교체 가능하게 함
15Template Method (템플릿 메서드)알고리즘의 뼈대를 정의하고, 세부 구현은 하위 클래스에 위임
16Command (커맨드)요청을 객체로 캡슐화해 실행 취소/재실행 등을 지원
17State (상태)객체 내부 상태에 따라 행위를 자동으로 변경
18Chain of Responsibility요청을 처리할 수 있는 객체를 체인으로 연결해 순차 전달
19Iterator (이터레이터)내부 구현 노출 없이 컬렉션 요소에 순차적으로 접근
20Mediator (미디에이터)객체 간 통신을 중재자를 통해 처리해 결합도 낮춤
21Memento (메멘토)객체의 이전 상태를 저장해 복원(undo) 기능 구현
22Interpreter (인터프리터)특정 언어의 문법을 클래스로 표현하고 해석
23Visitor (비지터)객체 구조를 변경하지 않고 새로운 연산을 추가

각 패턴의 예시


🏗️ 생성 패턴 (Creational)

1. Singleton — 단 하나의 인스턴스

javapublic class DatabaseConnection {
    private static DatabaseConnection instance;

    private DatabaseConnection() {}

    public static DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }
}

// 사용: 어디서 호출해도 동일한 객체
DatabaseConnection db1 = DatabaseConnection.getInstance();
DatabaseConnection db2 = DatabaseConnection.getInstance();
System.out.println(db1 == db2); // true

getInstance()를 통해 항상 동일한 객체를 반환합니다.


2. Factory Method — 하위 클래스가 객체 생성 결정

javainterface Animal {
    void speak();
}
class Dog implements Animal {
    public void speak() { System.out.println("멍멍!"); }
}
class Cat implements Animal {
    public void speak() { System.out.println("야옹!"); }
}

class AnimalFactory {
    public static Animal create(String type) {
        if (type.equals("dog")) return new Dog();
        else return new Cat();
    }
}

// 사용
Animal a = AnimalFactory.create("dog");
a.speak(); // 멍멍!

클라이언트는 구체 클래스를 몰라도 객체를 생성할 수 있습니다.


3. Abstract Factory — 관련 객체 집합 생성

javainterface Button { void click(); }
interface Checkbox { void check(); }

class WindowsButton implements Button { public void click() { System.out.println("Windows 버튼"); } }
class MacButton implements Button { public void click() { System.out.println("Mac 버튼"); } }

interface GUIFactory {
    Button createButton();
}
class WindowsFactory implements GUIFactory {
    public Button createButton() { return new WindowsButton(); }
}
class MacFactory implements GUIFactory {
    public Button createButton() { return new MacButton(); }
}

OS에 맞는 UI 컴포넌트 세트를 한 번에 생성할 수 있습니다.


4. Builder — 단계별 객체 생성

javaclass Pizza {
    String size, crust, topping;

    static class Builder {
        String size, crust, topping;
        Builder size(String s) { this.size = s; return this; }
        Builder crust(String c) { this.crust = c; return this; }
        Builder topping(String t) { this.topping = t; return this; }
        Pizza build() {
            Pizza p = new Pizza();
            p.size = size; p.crust = crust; p.topping = topping;
            return p;
        }
    }
}

// 사용
Pizza pizza = new Pizza.Builder()
    .size("Large").crust("씬").topping("페퍼로니").build();

복잡한 객체를 메서드 체이닝으로 유연하게 생성합니다.


5. Prototype — 기존 객체 복사

javaclass Character implements Cloneable {
    String name;
    int level;

    public Character clone() throws CloneNotSupportedException {
        return (Character) super.clone();
    }
}

// 사용
Character hero = new Character();
hero.name = "전사"; hero.level = 50;

Character clone = hero.clone(); // 복사
clone.name = "복제 전사";

객체를 처음부터 새로 만드는 대신 복사해 성능을 절약합니다.


🔩 구조 패턴 (Structural)

6. Adapter — 인터페이스 변환

java// 기존 클래스 (220V)
class KoreanSocket {
    public void connect220V() { System.out.println("220V 연결"); }
}

// 목표 인터페이스 (110V)
interface USASocket {
    void connect110V();
}

// 어댑터
class SocketAdapter implements USASocket {
    KoreanSocket korean = new KoreanSocket();
    public void connect110V() {
        korean.connect220V(); // 내부에서 변환
    }
}

JDBC가 대표적인 어댑터 패턴 사례로, 다양한 DB를 공통 인터페이스로 연결합니다.


7. Bridge — 구현과 추상 분리

javainterface Color { String fill(); }
class Red implements Color { public String fill() { return "빨간색"; } }
class Blue implements Color { public String fill() { return "파란색"; } }

abstract class Shape {
    Color color;
    Shape(Color c) { this.color = c; }
    abstract void draw();
}
class Circle extends Shape {
    Circle(Color c) { super(c); }
    public void draw() { System.out.println(color.fill() + " 원"); }
}

// 사용
new Circle(new Red()).draw(); // 빨간색 원
new Circle(new Blue()).draw(); // 파란색 원

도형과 색상을 독립적으로 확장할 수 있습니다.


8. Composite — 트리 구조 (개별·복합 동일 취급)

javainterface FileSystem {
    void show(String indent);
}
class File implements FileSystem {
    String name;
    File(String n) { name = n; }
    public void show(String indent) { System.out.println(indent + name); }
}
class Folder implements FileSystem {
    String name;
    List<FileSystem> children = new ArrayList<>();
    Folder(String n) { name = n; }
    void add(FileSystem f) { children.add(f); }
    public void show(String indent) {
        System.out.println(indent + "[" + name + "]");
        for (FileSystem f : children) f.show(indent + "  ");
    }
}

파일 시스템처럼 폴더 안에 파일/폴더를 재귀적으로 구성합니다.


9. Decorator — 동적으로 기능 추가

javainterface Coffee { int cost(); }
class BasicCoffee implements Coffee { public int cost() { return 1000; } }

class MilkDecorator implements Coffee {
    Coffee coffee;
    MilkDecorator(Coffee c) { this.coffee = c; }
    public int cost() { return coffee.cost() + 500; }
}
class ShotDecorator implements Coffee {
    Coffee coffee;
    ShotDecorator(Coffee c) { this.coffee = c; }
    public int cost() { return coffee.cost() + 300; }
}

// 사용
Coffee order = new ShotDecorator(new MilkDecorator(new BasicCoffee()));
System.out.println(order.cost()); // 1800원

기존 코드 수정 없이 기능을 겹겹이 추가합니다.


10. Facade — 복잡한 시스템을 단순 인터페이스로

javaclass CPU { void start() { System.out.println("CPU 시작"); } }
class Memory { void load() { System.out.println("메모리 로드"); } }
class Disk { void read() { System.out.println("디스크 읽기"); } }

// 퍼사드
class Computer {
    CPU cpu = new CPU();
    Memory mem = new Memory();
    Disk disk = new Disk();

    void turnOn() { // 복잡한 내부를 하나로 감춤
        cpu.start(); mem.load(); disk.read();
    }
}

new Computer().turnOn(); // 한 줄로 컴퓨터 시작

사용자는 내부 동작을 몰라도 됩니다.


11. Flyweight — 공유로 메모리 최적화

javaclass TreeType { // 공유 객체 (나무 종류)
    String name, color;
    TreeType(String n, String c) { name = n; color = c; }
}
class TreeFactory {
    static Map<String, TreeType> cache = new HashMap<>();
    static TreeType get(String name, String color) {
        return cache.computeIfAbsent(name, k -> new TreeType(name, color));
    }
}
// 1000그루 나무도 TreeType은 몇 개만 공유

대량의 유사 객체를 공유해 메모리를 아낍니다.


12. Proxy — 대리자 제공

javainterface Image { void display(); }

class RealImage implements Image {
    String file;
    RealImage(String f) { file = f; System.out.println(f + " 로딩..."); }
    public void display() { System.out.println(file + " 표시"); }
}
class ProxyImage implements Image {
    String file;
    RealImage real;
    ProxyImage(String f) { file = f; }
    public void display() {
        if (real == null) real = new RealImage(file); // 지연 로딩
        real.display();
    }
}

실제 객체는 필요할 때만 생성합니다(지연 로딩).


🔄 행위 패턴 (Behavioral)

13. Observer — 상태 변화 알림

javainterface Observer { void update(float temp); }

class WeatherStation {
    List<Observer> observers = new ArrayList<>();
    float temperature;
    void addObserver(Observer o) { observers.add(o); }
    void setTemperature(float t) {
        temperature = t;
        observers.forEach(o -> o.update(t)); // 전체 알림
    }
}
class Display implements Observer {
    public void update(float temp) { System.out.println("현재 온도: " + temp); }
}

유튜브 구독 알림처럼, 변화를 등록된 모든 구독자에게 자동 전파합니다.


14. Strategy — 알고리즘 교체

javainterface SortStrategy { void sort(int[] arr); }
class BubbleSort implements SortStrategy {
    public void sort(int[] arr) { System.out.println("버블 정렬"); }
}
class QuickSort implements SortStrategy {
    public void sort(int[] arr) { System.out.println("퀵 정렬"); }
}

class Sorter {
    SortStrategy strategy;
    Sorter(SortStrategy s) { strategy = s; }
    void sort(int[] arr) { strategy.sort(arr); }
}

// 사용
Sorter sorter = new Sorter(new QuickSort());
sorter.sort(new int[]{3,1,2}); // 퀵 정렬

런타임에 알고리즘을 자유롭게 교체합니다.


15. Template Method — 알고리즘 뼈대 고정

javaabstract class DataProcessor {
    final void process() { // 순서 고정
        readData(); processData(); writeData();
    }
    abstract void readData();
    abstract void processData();
    void writeData() { System.out.println("파일에 저장"); } // 기본 구현
}
class CSVProcessor extends DataProcessor {
    void readData() { System.out.println("CSV 읽기"); }
    void processData() { System.out.println("CSV 파싱"); }
}

전체 흐름은 부모가 제어하고, 세부 구현만 자식이 담당합니다.


16. Command — 요청을 객체로 캡슐화

javainterface Command { void execute(); }

class Light {
    void on() { System.out.println("불 켜짐"); }
    void off() { System.out.println("불 꺼짐"); }
}
class LightOnCommand implements Command {
    Light light;
    LightOnCommand(Light l) { light = l; }
    public void execute() { light.on(); }
}

class RemoteControl {
    Command command;
    void setCommand(Command c) { command = c; }
    void pressButton() { command.execute(); }
}

실행 취소(Undo), 로깅, 큐 처리 등에 활용됩니다.


17. State — 상태에 따라 행동 변경

javainterface State { void handle(); }
class GreenLight implements State { public void handle() { System.out.println("직진"); } }
class RedLight implements State { public void handle() { System.out.println("정지"); } }

class TrafficLight {
    State state = new GreenLight();
    void setState(State s) { state = s; }
    void action() { state.handle(); }
}

조건문 없이 상태 객체 교체만으로 행동이 바뀝니다.


18. Chain of Responsibility — 요청을 체인으로 전달

javaabstract class Approver {
    Approver next;
    void setNext(Approver a) { next = a; }
    abstract void approve(int amount);
}
class Manager extends Approver {
    public void approve(int amount) {
        if (amount <= 100000) System.out.println("팀장 승인");
        else if (next != null) next.approve(amount);
    }
}
class CEO extends Approver {
    public void approve(int amount) { System.out.println("대표 승인"); }
}
// manager.setNext(ceo) → 결재 라인 구성

결재 라인처럼 처리 가능한 객체가 나올 때까지 요청을 전달합니다.


19. Iterator — 내부 구조 노출 없이 순회

javaclass NumberList implements Iterable<Integer> {
    int[] numbers = {1, 2, 3, 4, 5};

    public Iterator<Integer> iterator() {
        return new Iterator<>() {
            int index = 0;
            public boolean hasNext() { return index < numbers.length; }
            public Integer next() { return numbers[index++]; }
        };
    }
}

// 사용 (향상된 for문도 동일)
for (int n : new NumberList()) System.out.println(n);

Java의 for-each가 바로 이터레이터 패턴을 사용합니다.


20. Mediator — 중재자를 통한 통신

javaclass ChatRoom { // 중재자
    static void sendMessage(String user, String msg) {
        System.out.println("[" + user + "]: " + msg);
    }
}
class User {
    String name;
    User(String n) { name = n; }
    void send(String msg) { ChatRoom.sendMessage(name, msg); }
}
// 사용자들이 직접 연결되지 않고 채팅방을 통해 소통

객체들이 직접 참조하지 않고 중재자를 통해 통신해 결합도를 낮춥니다.


21. Memento — 상태 저장 및 복원 (Undo)

javaclass Editor {
    String text = "";

    String save() { return text; } // 저장
    void restore(String saved) { text = saved; } // 복원
    void write(String t) { text += t; }
}

// 사용
Editor e = new Editor();
e.write("안녕");
String saved = e.save(); // 저장
e.write("하세요");
System.out.println(e.text); // 안녕하세요
e.restore(saved);
System.out.println(e.text); // 안녕 (Undo)

텍스트 에디터의 Ctrl+Z 기능과 동일한 원리입니다.


22. Interpreter — 문법 해석

javainterface Expression { boolean interpret(String context); }

class TerminalExpression implements Expression {
    String data;
    TerminalExpression(String d) { data = d; }
    public boolean interpret(String context) { return context.contains(data); }
}
class OrExpression implements Expression {
    Expression e1, e2;
    OrExpression(Expression a, Expression b) { e1 = a; e2 = b; }
    public boolean interpret(String context) { return e1.interpret(context) || e2.interpret(context); }
}
// "자바" OR "파이썬" 포함 여부 판별

SQL 파서, 수식 계산기 등에 활용되는 패턴입니다.


23. Visitor — 구조 변경 없이 새 연산 추가

javainterface Visitor { void visit(Circle c); void visit(Rectangle r); }
interface Shape { void accept(Visitor v); }

class Circle implements Shape {
    double radius;
    Circle(double r) { radius = r; }
    public void accept(Visitor v) { v.visit(this); }
}
class AreaCalculator implements Visitor {
    public void visit(Circle c) { System.out.println("원 넓이: " + Math.PI * c.radius * c.radius); }
    public void visit(Rectangle r) { /* ... */ }
}

도형 클래스를 건드리지 않고, Visitor만 추가해 새로운 연산을 구현합니다.