컴파운드 패턴

DesignPartterns - 컴파운드 패턴

4 minute read

컴파운드 패턴이란?

반복적으로 생길 수 있는 일반적인 문제를 해결하기 위한 용도로 두 개 이상의 패턴을 결합해서 사용하는 것. 패턴을 같이 쓴다고 무조건 컴파운드 패턴은 아니다. 문제를 해결하기 위한 용도로 사용해야 된다. 대표적인 컴파운드 패턴은 MVC이다.


//Quckable인터페이스를 구현한 클래스들

public interface Quackable {
    public void quack();
}

public class DuckCall implements Quackable{
    @Override
    public void quack() {
        System.out.println("Kwak");
    }
}

public class MallardDuck implements Quackable {
    @Override
    public void quack() {
        System.out.println("Quack");
    }
}

public class RedheadDuck implements Quackable {
    @Override
    public void quack() {
        System.out.println("quack");
    }
}

public class RubberDuck implements Quackable{
    @Override
    public void quack() {
        System.out.println("Squeak");
    }
}
  • 실행

    public class DuckSimulator {
    
    
    public static void main(String [] args) {
        DuckSimulator simulator = new DuckSimulator();
        simulator.simulator();
    }
    
    
    void simulator() {
        Quackable mallardDuck = new MallardDuck();
        Quackable redheadDuck = new RedheadDuck();
        Quackable duckCall = new DuckCall();
        Quackable rubberDuck = new RubberDuck();
    
    
        System.out.println("\nDuck Simulator");
    
    
        simulator(mallardDuck);
        simulator(redheadDuck);
        simulator(duckCall);
        simulator(rubberDuck);
    }
    
    
    void simulator(Quackable duck) {
        duck.quack();
    }
    }
    ---------------------------------
    Duck Simulator
    Quack
    quack
    Kwak
    Squeak
    
  • 거위가 추가되었다.

    public class Goose {
    public void honk() {
        System.out.println("Honk");
    }
    }
    
  • Duck를 집어 넣을 수 있는 곳이라면 어디든지 Goose도 집어 넣을 수 있어야 한다고 가정한다. 하지만 클래스가 다른데 거위를 시뮬레이터에 집어 넣어야 한다. 어떻게 해야 거위를 오리와 어울리게 할 수 있을까??

  • 거위용 어댑터를 만들면 된다.

public class GooseAdapter implements Quackable {

    Goose goose;
    
    public GooseAdapter(Goose goose) {
        this.goose = goose;
    }
    
    @Override
    public void quack() {
        goose.honk();
    }
}

//DuckSimulator
Quackable gooseDuck = new GooseAdapter(new Goose());

어댑터 패턴(Adapter Pattern)의 정의

  • 한 클래스(어떤)의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환한다. 어탭터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있습니다.
  • 어댑터는 클라이언트로부터 요청을 받아서 새로운 업체에서 제공하는 클래스에서 받아들일 수 있는 형태의 요청으로 변환시켜주는 중개인 역할을 한다.

  • 꽥소리를 낸 횟수를 세주는 기능을 추가해야 한다.

  • 어떻게 해야할까??

  • 소리의 횟수를 세는 기능을 가진 데코레이터 객체를 만들어서 오리 객체들을 감싸면 된다. 그러면 Duck객체들을 건드리지 않아도 된다.

//데코레이터 객체
public class QuackCounter implements Quackable{
    Quackable duck;
    static int numberOfQuacks;
    
    public QuackCounter(Quackable duck) {
        this.duck = duck;
    }
    
    @Override
    public void quack() {
        duck.quack();
        numberOfQuacks++;
    }

    public static int getQuacks() {
        return numberOfQuacks;
    }
}

//실행
public class DuckSimulator {
    
    public static void main(String [] args) {
        DuckSimulator simulator = new DuckSimulator();
        simulator.simulator();
    }
    
    
    void simulator() {
        Quackable mallardDuck = new QuackCounter(new MallardDuck());
        Quackable redheadDuck = new QuackCounter(new RedheadDuck());
        Quackable duckCall = new QuackCounter(new DuckCall());
        Quackable rubberDuck = new QuackCounter(new RubberDuck());
        Quackable gooseDuck = new GooseAdapter(new Goose());
        
        System.out.println("\nDuck Simulator");
        
        simulator(mallardDuck);
        simulator(redheadDuck);
        simulator(duckCall);
        simulator(rubberDuck);
        simulator(gooseDuck);
        
        System.out.println("The Ducks quacked " + QuackCounter.getQuacks() + " times");
    }
    
    void simulator(Quackable duck) {
        duck.quack();
    }
}

-----------------------------
Duck Simulator
Quack
quack
Kwak
Squeak
Honk
The Ducks quacked 4 times

Decorator Pattern의 정의

  • 데코레이터 패턴에서는 객체에 추가적인 요건을 동적으로 첨가한다. (즉 자신이 장식하고 있는 객체에게 어떤 행동을 위임하는 것 외에 원하는 추가적인 작업을 수행할 수 있다.)
  • 데코레이터는 서브클래스를 만드는 것을 통해서 기능을 유연하게 확장할 수 있는 방법을 제공한다.
  • 한마디로 기존 구현되어있는 클래스에 기능을 추가하기위한 패턴이다.

  • 새로운 문제점
  • 데코레이터를 쓸 때는 객체들을 제대로 포장하지 않으면 원하는 행동을 추가할 수 없다.
  • 그렇다면 오리 객체를 생성하는 작업을 한 군데에 몰아서 하는건 어떨까? 오리를 생성하고 데코레이터로 감싸는 부분을 따로 빼내서 캡슐화를 하자.
  • 모든 오리들이 데코레이터로 감싸지도록 할 수 있는 방법이 필요하다. 그렇게 하는 데는 팩토리를 만드는게 제격이다. 이 팩토리에서는 여러 종류의 오리들을 생산해야 할 테니깐 추상 팩토리 패턴을 사용하자
public abstract class AbstractDuckFactory {
    
    public abstract Quackable createMallardDuck();
    public abstract Quackable createRedheadDuck();
    public abstract Quackable createDuckCall();
    public abstract Quackable createRubberDuck();
}

public class CountingDuckFactory extends AbstractDuckFactory{

    @Override
    public Quackable createMallardDuck() {
        return new QuackCounter(new MallardDuck());
    }

    @Override
    public Quackable createRedheadDuck() {
        return new QuackCounter(new RedheadDuck());
    }

    @Override
    public Quackable createDuckCall() {
        return new QuackCounter(new DuckCall());
    }

    @Override
    public Quackable createRubberDuck() {
        return new QuackCounter(new RubberDuck());
    }
}

public class DuckSimulator {
    
    public static void main(String [] args) {
        DuckSimulator simulator = new DuckSimulator();
        AbstractDuckFactory duckFactory = new CountingDuckFactory();
        simulator.simulator(duckFactory);
    }
    
    
    void simulator(AbstractDuckFactory duckFactory) {
        Quackable mallardDuck = duckFactory.createMallardDuck();
        Quackable redheadDuck = duckFactory.createRedheadDuck();
        Quackable duckCall = duckFactory.createDuckCall();
        Quackable rubberDuck = duckFactory.createRubberDuck();
        Quackable gooseDuck = new GooseAdapter(new Goose());
        
        System.out.println("\nDuck Simulator");
        
        simulator(mallardDuck);
        simulator(redheadDuck);
        simulator(duckCall);
        simulator(rubberDuck);
        simulator(gooseDuck);
        
        System.out.println("The Ducks quacked " + QuackCounter.getQuacks() + " times");
    }
    
    void simulator(Quackable duck) {
        duck.quack();
    }
}

##추상 팩토리 (Abstract Factory)

구체적인 클래스를 지정하지 않고 관련성을 갖는 객체들의 집합을 생성하거나 서로 독립적인 객체들의 집합을 생성할 수 있는 인터페이스를 제공한다.


위와 같이 문제를 해결하기 위해서 여러 패턴을 사용하는 것이 컴파운드 패턴이다.

comments powered by Disqus