Java 23가지 디자인 패턴 핵심 요약 및 구현 가이드

1. 생성 패턴 (Creational Patterns)

객체 생성 프로세스를 추상화하여 시스템이 객체 생성, 구성, 표현 방식에 독립적일 수 있도록 돕습니다.

1.1 싱글톤 패턴 (Singleton)

클래스의 인스턴스가 오직 하나만 생성되도록 보장하고 이에 대한 전역적인 접근점을 제공합니다.

// Bill Pugh Singleton (권장되는 방식)
public class AppConfig {
    private AppConfig() {}

    private static class Holder {
        private static final AppConfig INSTANCE = new AppConfig();
    }

    public static AppConfig getInstance() {
        return Holder.INSTANCE;
    }
}

1.2 팩토리 메서드 패턴 (Factory Method)

객체 생성 인터페이스를 정의하되, 실제 어떤 클래스의 인스턴스를 생성할지는 서브클래스에서 결정하게 합니다.

interface Vehicle { void drive(); }

class Truck implements Vehicle {
    public void drive() { System.out.println("트럭이 달립니다."); }
}

abstract class VehicleFactory {
    abstract Vehicle createVehicle();
}

class TruckFactory extends VehicleFactory {
    Vehicle createVehicle() { return new Truck(); }
}

1.3 추상 팩토리 패턴 (Abstract Factory)

관련성이 있는 여러 객체 군을 생성하기 위한 인터페이스를 제공하며, 구체적인 클래스를 명시하지 않고 제품군을 생성합니다.

interface Button { void render(); }
interface ScrollBar { void scroll(); }

interface GuiFactory {
    Button createButton();
    ScrollBar createScrollBar();
}

class DarkThemeFactory implements GuiFactory {
    public Button createButton() { return () -> System.out.println("Dark Button"); }
    public ScrollBar createScrollBar() { return () -> System.out.println("Dark Scroll"); }
}

1.4 빌더 패턴 (Builder)

복잡한 객체의 생성 과정과 표현 방법을 분리하여 동일한 생성 절차에서 서로 다른 표현을 만들 수 있게 합니다.

public class User {
    private final String name;
    private final int age;

    public static class Builder {
        private String name;
        private int age;

        public Builder name(String name) { this.name = name; return this; }
        public Builder age(int age) { this.age = age; return this; }
        public User build() { return new User(this); }
    }

    private User(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
    }
}

1.5 프로토타입 패턴 (Prototype)

원형이 되는 인스턴스를 사용하여 객체를 복사함으로써 새로운 객체를 생성합니다.

class Document implements Cloneable {
    String content;
    public Document clone() throws CloneNotSupportedException {
        return (Document) super.clone();
    }
}

2. 구조 패턴 (Structural Patterns)

클래스나 객체를 조합하여 더 큰 구조를 만드는 방법론입니다.

2.1 어댑터 패턴 (Adapter)

호환되지 않는 인터페이스를 가진 클래스들이 함께 작동할 수 있도록 중간에서 변환해줍니다.

interface PowerOutlet { void supply5V(); }

class WallSocket { void supply220V() { /* ... */ } }

class VoltageAdapter implements PowerOutlet {
    private WallSocket socket = new WallSocket();
    public void supply5V() {
        socket.supply220V();
        System.out.println("5V로 변환 중...");
    }
}

2.2 브릿지 패턴 (Bridge)

추상화된 부분과 구현 부분을 독립적으로 확장할 수 있도록 연결합니다.

interface Color { void apply(); }

abstract class Shape {
    protected Color color;
    protected Shape(Color color) { this.color = color; }
    abstract void draw();
}

class Square extends Shape {
    public Square(Color color) { super(color); }
    void draw() { System.out.print("정사각형 "); color.apply(); }
}

2.3 컴포지트 패턴 (Composite)

객체들을 트리 구조로 구성하여 개별 객체와 복합 객체를 동일하게 다룰 수 있게 합니다.

interface FileSystemNode { void printName(); }

class File implements FileSystemNode {
    private String name;
    public File(String name) { this.name = name; }
    public void printName() { System.out.println("File: " + name); }
}

class Directory implements FileSystemNode {
    private List<FileSystemNode> nodes = new ArrayList<>();
    public void add(FileSystemNode node) { nodes.add(node); }
    public void printName() { nodes.forEach(FileSystemNode::printName); }
}

2.4 데코레이터 패턴 (Decorator)

객체에 동적으로 새로운 책임을 추가하며, 서브클래스를 만드는 것보다 유연한 확장성을 제공합니다.

interface Beverage { String getDescription(); }

class BasicCoffee implements Beverage {
    public String getDescription() { return "커피"; }
}

class MilkDecorator implements Beverage {
    private Beverage beverage;
    public MilkDecorator(Beverage b) { this.beverage = b; }
    public String getDescription() { return beverage.getDescription() + " + 우유"; }
}

2.5 퍼사드 패턴 (Facade)

복잡한 서브시스템에 대해 단순화된 통합 인터페이스를 제공합니다.

class AudioSystem { void on() {} }
class VideoSystem { void on() {} }

class HomeTheaterFacade {
    private AudioSystem audio = new AudioSystem();
    private VideoSystem video = new VideoSystem();

    public void watchMovie() {
        video.on();
        audio.on();
    }
}

2.6 플라이웨이트 패턴 (Flyweight)

다수의 유사한 객체를 생성할 때 가능한 많은 데이터를 공유하여 메모리 사용량을 줄입니다.

class TreeType {
    private String name, color; // 공유 데이터
    public TreeType(String n, String c) { this.name = n; this.color = c; }
}

class TreeFactory {
    private static Map<String, TreeType> types = new HashMap<>();
    public static TreeType getTreeType(String name, String color) {
        return types.computeIfAbsent(name, k -> new TreeType(name, color));
    }
}

2.7 프록시 패턴 (Proxy)

특정 객체에 대한 접근을 제어하기 위해 대리자 객체를 둡니다.

interface SensitiveData { void access(); }

class RealData implements SensitiveData {
    public void access() { System.out.println("데이터 접근 완료"); }
}

class DataProxy implements SensitiveData {
    private RealData realData;
    public void access() {
        if (realData == null) realData = new RealData();
        System.out.println("보안 체크 중...");
        realData.access();
    }
}

3. 행위 패턴 (Behavioral Patterns)

객체 간의 알고리즘이나 책임 분배에 관련된 패턴입니다.

3.1 책임 연쇄 패턴 (Chain of Responsibility)

요청을 처리할 수 있는 기회를 하나 이상의 객체에게 부여하여 요청자와 처리자를 분리합니다.

abstract class Logger {
    protected Logger next;
    public void setNext(Logger next) { this.next = next; }
    abstract void log(String msg, int level);
}

class ErrorLogger extends Logger {
    void log(String msg, int level) {
        if (level == 3) System.out.println("Error: " + msg);
        else if (next != null) next.log(msg, level);
    }
}

3.2 커맨드 패턴 (Command)

요청을 객체의 형태로 캡슐화하여 요청을 매개변수화하거나 로그에 남길 수 있게 합니다.

interface Command { void execute(); }

class LightOnCommand implements Command {
    private Light light;
    public LightOnCommand(Light l) { this.light = l; }
    public void execute() { light.turnOn(); }
}

3.3 인터프리터 패턴 (Interpreter)

특정 언어의 문법 표현과 이를 해석하는 인터프리터를 정의합니다.

interface Expression { boolean interpret(String context); }

class ContainsExpression implements Expression {
    private String data;
    public ContainsExpression(String d) { this.data = d; }
    public boolean interpret(String context) { return context.contains(data); }
}

3.4 반복자 패턴 (Iterator)

내부 구조를 노출하지 않고 컬렉션의 요소들에 순차적으로 접근할 수 있는 방법을 제공합니다.

interface MyIterator { boolean hasNext(); Object next(); }

class NameList {
    String[] names = {"Lee", "Kim", "Park"};
    public MyIterator getIterator() {
        return new MyIterator() {
            int i = 0;
            public boolean hasNext() { return i < names.length; }
            public Object next() { return names[i++]; }
        };
    }
}

3.5 중재자 패턴 (Mediator)

객체들 간의 복잡한 상호작용을 중재자 객체에 캡슐화하여 객체 간의 결합도를 낮춥니다.

interface ChatRoom { void send(String msg, User user); }

class ChatRoomImpl implements ChatRoom {
    public void send(String msg, User user) {
        System.out.println(user.getName() + ": " + msg);
    }
}

3.6 메멘토 패턴 (Memento)

캡슐화를 위배하지 않고 객체의 상태를 저장하고 나중에 복구할 수 있게 합니다.

class GameState {
    private String level;
    public Memento save() { return new Memento(level); }
    public void restore(Memento m) { level = m.getState(); }
}

class Memento {
    private final String state;
    public Memento(String s) { this.state = s; }
    public String getState() { return state; }
}

3.7 옵저버 패턴 (Observer)

객체의 상태가 변할 때 의존 관계에 있는 모든 객체들에게 자동으로 통지합니다.

interface Subscriber { void update(String news); }

class NewsAgency {
    private List<Subscriber> subs = new ArrayList<>();
    public void broadcast(String news) {
        subs.forEach(s -> s.update(news));
    }
}

3.8 상태 패턴 (State)

객체의 내부 상태에 따라 스스로 행동을 변경할 수 있게 합니다.

interface State { void handle(); }

class PlayState implements State {
    public void handle() { System.out.println("재생 중..."); }
}

class PlayerContext {
    private State state;
    public void setState(State s) { this.state = s; }
    public void request() { state.handle(); }
}

3.9 전략 패턴 (Strategy)

동일 계열의 알고리즘들을 정의하고 캡슐화하여 실행 중에 알고리즘을 선택할 수 있게 합니다.

interface PaymentStrategy { void pay(int amount); }

class CreditCardStrategy implements PaymentStrategy {
    public void pay(int amount) { System.out.println(amount + " 카드 결제"); }
}

class ShoppingCart {
    public void checkout(int amount, PaymentStrategy strategy) {
        strategy.pay(amount);
    }
}

3.10 템플릿 메서드 패턴 (Template Method)

알고리즘의 구조를 정의하고 구체적인 단계는 서브클래스에서 구현하도록 위임합니다.

abstract class DataProcessor {
    public final void process() {
        read();
        transform();
        write();
    }
    abstract void read();
    abstract void transform();
    void write() { System.out.println("데이터 저장 완료"); }
}

3.11 방문자 패턴 (Visitor)

객체 구조를 변경하지 않고 새로운 작업을 객체에 추가할 수 있게 합니다.

interface Element { void accept(Visitor v); }

interface Visitor { void visit(Book b); }

class Book implements Element {
    public void accept(Visitor v) { v.visit(this); }
}

태그: java DesignPatterns OOP SoftwareArchitecture

7월 15일 00:38에 게시됨