컴파운드 패턴이란?

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

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


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