복합 패턴 (Compound Pattern)

Bo Ram·2025년 4월 20일

2-1. 의도

복합 패턴은 여러 디자인 패턴을 조합해서 복잡한 시스템을 설계할 수 있도록 하는 패턴 구성 방식임.
책에서는 "오리 시뮬레이터"를 통해 다양한 패턴을 조합하여 확장 가능하고 유연한 시스템을 만들어냄.


2-2. 사용된 패턴 요약

사용된 패턴역할
팩토리 패턴오리 객체 생성 캡슐화
데코레이터 패턴울음 횟수 세기 기능 추가
어댑터 패턴거위를 오리처럼 사용 가능하게 함
컴포지트 패턴오리 그룹을 하나의 오리처럼 사용
옵저버 패턴오리가 울면 옵저버에게 알림 전파

2-3. 시뮬레이터 흐름 요약

  1. 오리 객체를 공장(DuckFactory)을 통해 생성
  2. QuackCounter로 감싸서 울음 횟수 추적
  3. GooseAdapter로 거위를 오리로 감쌈
  4. 여러 오리를 Flock으로 묶음
  5. Quackologist를 옵저버로 등록
  6. simulate()를 통해 모든 오리가 울도록 함

2-4. 핵심 클래스 구조

// 인터페이스
interface Quackable extends QuackObservable {
    void quack();
}

// 기본 오리
class MallardDuck implements Quackable {
    Observable observable = new Observable(this);

    public void quack() {
        System.out.println("꽥");
        notifyObservers();
    }

    public void registerObserver(Observer observer) {
        observable.registerObserver(observer);
    }

    public void notifyObservers() {
        observable.notifyObservers();
    }
}

데코레이터: QuackCounter

class QuackCounter implements Quackable {
    Quackable duck;
    static int quackCount;

    public QuackCounter(Quackable duck) {
        this.duck = duck;
    }

    public void quack() {
        duck.quack();
        quackCount++;
    }

    public static int getQuacks() {
        return quackCount;
    }

    public void registerObserver(Observer observer) {
        duck.registerObserver(observer);
    }

    public void notifyObservers() {
        duck.notifyObservers();
    }
}

어댑터: GooseAdapter

class Goose {
    public void honk() {
        System.out.println("끽");
    }
}

class GooseAdapter implements Quackable {
    Goose goose;
    Observable observable = new Observable(this);

    public GooseAdapter(Goose goose) {
        this.goose = goose;
    }

    public void quack() {
        goose.honk();
        notifyObservers();
    }

    public void registerObserver(Observer observer) {
        observable.registerObserver(observer);
    }

    public void notifyObservers() {
        observable.notifyObservers();
    }
}

컴포지트: Flock

class Flock implements Quackable {
    List<Quackable> quackers = new ArrayList<>();

    public void add(Quackable quacker) {
        quackers.add(quacker);
    }

    public void quack() {
        for (Quackable quacker : quackers) {
            quacker.quack();
        }
    }

    public void registerObserver(Observer observer) {
        for (Quackable quacker : quackers) {
            quacker.registerObserver(observer);
        }
    }

    public void notifyObservers() {
        // Flock은 직접 notify하지 않음. 각 quacker가 notify
    }
}

옵저버

interface Observer {
    void update(QuackObservable duck);
}

interface QuackObservable {
    void registerObserver(Observer observer);
    void notifyObservers();
}

class Observable implements QuackObservable {
    List<Observer> observers = new ArrayList<>();
    QuackObservable duck;

    public Observable(QuackObservable duck) {
        this.duck = duck;
    }

    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(duck);
        }
    }
}

옵저버 구현: Quackologist

class Quackologist implements Observer {
    public void update(QuackObservable duck) {
        System.out.println("관찰자: " + duck + " 가 방금 울었음");
    }
}

2-5. 정리

  • 단일 패턴으로는 해결할 수 없는 복잡한 요구사항도, 여러 패턴을 조합하면 깔끔하게 처리 가능
  • 각 패턴이 자기 역할에만 집중하고, 결합도가 낮고 유연성 높음
  • 실전 프로젝트에서도 다양한 패턴 조합은 필수
profile
사부작ㅤ사부작

0개의 댓글