ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 구조 패턴(Structural Pattern) - 데코레이터(Decorator) 패턴
    Java/디자인패턴 2024. 11. 20. 09:25
    반응형

    1. 소속 카테고리

    데코레이터 패턴은 **구조 패턴(Structural Pattern)**에 속합니다. 구조 패턴은 클래스나 객체를 조합하여 더 큰 구조를 형성하거나, 객체 간의 관계를 효율적으로 구성하는 데 초점을 맞춥니다.


    2. 특징

    • 객체에 동적으로 새로운 기능을 추가할 수 있습니다.
    • 기존 객체를 수정하지 않고도 기능 확장이 가능하여 **개방-폐쇄 원칙(OCP)**을 준수합니다.
    • 상속을 사용하지 않고도 유연하게 기능을 확장할 수 있습니다.

    3. 주요 구성 요소

    1. Component (기본 인터페이스/추상 클래스): 기본 객체의 공통된 인터페이스를 정의합니다.
    2. ConcreteComponent: 기본 객체로, 기본 동작을 구현합니다.
    3. Decorator: Component를 구현하거나 상속받아 동적으로 기능을 추가할 수 있는 클래스입니다.
    4. ConcreteDecorator: Decorator의 구체적인 구현체로, 추가된 동작을 정의합니다.

    4. Java 예제

    요구 사항:

    커피(Coffee) 주문 시스템을 구현해야 합니다.

    • 기본 커피에 우유, 설탕 등 추가 옵션을 동적으로 선택할 수 있어야 합니다.
    • 각 옵션은 가격을 추가하며, 조합에 따라 가격이 계산됩니다.
    // Component 인터페이스
    public interface Coffee {
        String getDescription();
        double getCost();
    }
    
    // ConcreteComponent
    public class BasicCoffee implements Coffee {
        @Override
        public String getDescription() {
            return "Basic Coffee";
        }
    
        @Override
        public double getCost() {
            return 2.0; // 기본 커피 가격
        }
    }
    
    // Decorator
    public abstract class CoffeeDecorator implements Coffee {
        protected Coffee coffee;
    
        public CoffeeDecorator(Coffee coffee) {
            this.coffee = coffee;
        }
    
        @Override
        public String getDescription() {
            return coffee.getDescription();
        }
    
        @Override
        public double getCost() {
            return coffee.getCost();
        }
    }
    
    // ConcreteDecorator 1
    public class MilkDecorator extends CoffeeDecorator {
        public MilkDecorator(Coffee coffee) {
            super(coffee);
        }
    
        @Override
        public String getDescription() {
            return coffee.getDescription() + ", Milk";
        }
    
        @Override
        public double getCost() {
            return coffee.getCost() + 0.5; // 우유 추가 비용
        }
    }
    
    // ConcreteDecorator 2
    public class SugarDecorator extends CoffeeDecorator {
        public SugarDecorator(Coffee coffee) {
            super(coffee);
        }
    
        @Override
        public String getDescription() {
            return coffee.getDescription() + ", Sugar";
        }
    
        @Override
        public double getCost() {
            return coffee.getCost() + 0.2; // 설탕 추가 비용
        }
    }
    
    // Client 코드
    public class DecoratorPatternExample {
        public static void main(String[] args) {
            Coffee basicCoffee = new BasicCoffee();
            System.out.println(basicCoffee.getDescription() + " -> $" + basicCoffee.getCost());
    
            Coffee milkCoffee = new MilkDecorator(basicCoffee);
            System.out.println(milkCoffee.getDescription() + " -> $" + milkCoffee.getCost());
    
            Coffee milkSugarCoffee = new SugarDecorator(milkCoffee);
            System.out.println(milkSugarCoffee.getDescription() + " -> $" + milkSugarCoffee.getCost());
        }
    }

     

     

    5. 코드 실행 결과

    Basic Coffee -> $2.0
    Basic Coffee, Milk -> $2.5
    Basic Coffee, Milk, Sugar -> $2.7

     

     


    6. 장점

    1. 유연성: 기존 객체를 수정하지 않고도 기능 확장 가능.
    2. 재사용성: 다양한 데코레이터를 조합하여 새로운 동작을 쉽게 생성.
    3. 개방-폐쇄 원칙 준수: 새로운 데코레이터를 추가해도 기존 코드에 영향을 주지 않음.

    7. 단점

    1. 데코레이터를 많이 중첩하면 Java 코드가 복잡해질 수 있음.
    2. 디버깅이 어렵고, 객체 식별이 복잡해질 수 있음.
    반응형

    댓글

Designed by Tistory.