ComputerScience/디자인 패턴

[디자인 패턴] 데코레이트 패턴

slown 2024. 6. 5. 21:40

목차?

1.데코레이트 패턴?

2.데코레이트 패턴 장단점

3.데코레이트 구현

 

1.데코레이트 패턴?

데코레이트 패턴은 객체의 기능을 동적으로 추가하거나 확장할 수 있는 구조적 디자인 패턴입니다. 이 패턴은 상속 대신 객체 조합을 활용하여 기능을 확장하는 방식으로, 더 유연하고 유지보수성이 높은 코드를 작성할 수 있게 합니다.

2.데코레이트 패턴 장단점

데코레이트 패턴의 장단점은 다음과 같습니다.

 

장점

  1. 유연한 기능 확장:
    • 상속 대신 객체 조합을 통해 기능을 동적으로 추가하거나 제거할 수 있어, 매우 유연하게 기능을 확장할 수 있습니다.
    • 런타임에 객체의 행동을 변경할 수 있어, 다양한 요구사항을 쉽게 반영할 수 있습니다.
  2. 단일 책임 원칙 준수:
    • 각 클래스가 하나의 책임만 가지게 되므로, 클래스의 책임이 명확해지고 유지보수가 용이해집니다.
    • 기능 추가나 변경이 필요한 경우, 해당 기능을 담당하는 데코레이터 클래스만 수정하면 되므로, 코드의 수정이 쉬워집니다.
  3. 재사용성 향상:
    • 기능이 작은 단위로 분리되기 때문에, 각 데코레이터 클래스는 독립적으로 재사용될 수 있습니다.
    • 여러 데코레이터를 조합하여 다양한 기능을 쉽게 구현할 수 있습니다.
  4. 투명성:
    • 데코레이터 패턴은 클라이언트 코드에 투명하게 작동합니다. 클라이언트는 기본 객체와 데코레이터 객체를 구분하지 않고 사용할 수 있습니다.

단점

  1. 객체 수 증가:
    • 기능을 추가할 때마다 새로운 데코레이터 객체를 생성해야 하므로, 객체 수가 늘어날 수 있습니다.
    • 이는 메모리 사용량 증가와 객체 관리의 복잡성을 초래할 수 있습니다.
  2. 복잡성 증가:
    • 데코레이터가 많아지면 클래스 계층 구조가 복잡해질 수 있습니다.
    • 객체의 기능을 파악하기 위해 여러 데코레이터 클래스를 살펴봐야 하므로, 코드 이해도가 떨어질 수 있습니다.
  3. 디버깅 어려움:
    • 여러 데코레이터가 조합되어 작동하므로, 디버깅 과정에서 실제 객체의 상태나 동작을 추적하기 어려울 수 있습니다.
    • 중첩된 데코레이터들 사이에서 버그를 찾아내는 것이 어려울 수 있습니다.
  4. 호환성 문제:
    • 기존 코드에 새로운 데코레이터를 추가하는 과정에서, 데코레이터가 올바르게 적용되지 않으면 예상치 못한 동작을 할 수 있습니다.
    • 특히, 데코레이터가 여러 개 중첩되어 있을 때, 각 데코레이터가 올바르게 상호작용하는지 확인하는 것이 중요합니다.

3.데코레이트 구현

public interface Coffee {
	String getDescription();
    double getCost();
}

public class SimpleCoffee implements Coffee{

	@Override
	public String getDescription() {
		// TODO Auto-generated method stub
		return "Simple Coffee";
	}

	@Override
	public double getCost() {
		// TODO Auto-generated method stub
		return 5.0;
	}
	
}

public abstract class CoffeeDecorator implements Coffee{
	
	protected Coffee decoratedCoffee;
	
	public CoffeeDecorator(Coffee coffee) {
        this.decoratedCoffee = coffee;
    }

    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription();
    }

    @Override
    public double getCost() {
        return decoratedCoffee.getCost();
    }
}

public class MilkDecorator extends CoffeeDecorator {
	
	public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription() + ", Milk";
    }

    @Override
    public double getCost() {
        return decoratedCoffee.getCost() + 1.5;
    }
}

public class MochaDecorator extends CoffeeDecorator{
	
	public MochaDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription() + ", Mocha";
    }

    @Override
    public double getCost() {
        return decoratedCoffee.getCost() + 2.0;
    }
}

public class Client {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Coffee simpleCoffee = new SimpleCoffee();
        System.out.println(simpleCoffee.getDescription() + " $" + simpleCoffee.getCost());

        Coffee milkCoffee = new MilkDecorator(simpleCoffee);
        System.out.println(milkCoffee.getDescription() + " $" + milkCoffee.getCost());

        Coffee mochaCoffee = new MochaDecorator(milkCoffee);
        System.out.println(mochaCoffee.getDescription() + " $" + mochaCoffee.getCost());
	}

}