공부하고 기록하는, 경제학과 출신 개발자의 노트

학습일지/Language

[Design Pattern] Decorator

inspirit941 2020. 12. 22. 08:18
반응형

Decorator

객체 결합으로 기능을 동적으로 유연하게 확장할 수 있게 하는 패턴.

기본 기능에 추가할 수 있는 기능 종류가 많은 경우, 각 추가 기능을 Decorator 클래스로 정의한 뒤 필요한 Decorator 객체를 조합하는 식으로 설계함

  • 상속을 통해 확장할 수도 있지만, 디자인 유연성 면에서 상속은 비추천
  • 기존 코드를 수정하지 않고도 확장할 수 있도록 Decorator 패턴 사용

ex) 자바 입출력의 Filter Stream 기능.

단점

  • 자잘한 객체가 많이 추가되므로, Decorator 패턴을 너무 많이 사용할 경우 코드가 필요 이상으로 복잡해질 수 있다.
  • Component를 초기화하기 위한 코드가 복잡해진다. Decorator로 Wrapping해야 하는 경우가 종종 생김. 따라서 보통 Factory / Builder 패턴과 함께 사용된다.
public abstract class IceCream {
    protected String description = "";
    public String getDescription() { return this.description; }
    public abstract int price();
}

public class IceCreamCake extends IceCream {
    public IceCreamCake() { this.description = "케이크"; }
    @Override
    public int price() { return 1500; }
}

public class IceCreamCone extends IceCream {
    public IceCreamCone() { this.description = "콘"; }
    @Override
    public int price() { return 1200; }
}

// 데코레이터 패턴에 사용할 클래스
// 데코레이터 클래스의 형식은, 해당 클래스가 감싸고 있는 클래스 형식을 반영한다.
// 이 경우 IceCream 객체를 감싸고 있어야 하므로 IceCream을 상속한다.
public abstract class Decorator extends IceCream {
    public abstract String getDescription();
}

public class Vanilla extends Decorator {
    // Wrapping할 인스턴스를 저장
    IceCream iceCream;
    public Vanilla(IceCream iceCream) { this.iceCream = iceCream; }
    @Override
    public String getDescription() { return "바닐라" + iceCream.getDescription(); }
    @Override
    public int price() { return 500 + iceCream.price(); }
}


public class TestDecoratorPattern {
    public static void main(String[] args) {
        IceCream iceCream1 = new IceCreamCone();
        System.out.println(iceCream1.getDescription() + " Cost: " + icecream1.price()); // return 콘 Cost: 1200

        // Decorator Pattern으로 필요한 값을 Wrapping
        iceCream1 = new Vanilla(iceCream1);
        System.out.println(iceCream1.getDescription() + " Cost: " + iceCream1.price()); // return 바닐라콘 Cost: 1700
    }
}
// 기본이 되는 클래스는 일반 클래스 or 추상클래스
public abstract class Student {
    protected String description = "not specific";
    public String getDescription() {
        return description;
    }
}

public class KoreanStudent extends Student {
    public KoreanStudent() { this.description = "Korean"; }
}

// Decorator 패턴 적용하기
public abstract class StudentDecorator extends Student {
    // 서브클래스에서 description을 반드시 추가하도록 강제한다.
    public abstract String getDescription();
}

public class Art extends StudentDecorator {
    private Student student;
    public Art(Student student) { this.student = student; }
    @Override
    public String getDescription() { return student.getDescription() + " enrolls Art"; }
    public void draw() { System.out.println("drawing"); }
}

public class Science extends StudentDecorator {
    private Student student;
    public Science(Student student) { this.student = student; }
    @Override
    public String getDescription() { return student.getDescription() + " enrolls Science"; }
    public void calculate() { System.out.println("calculating"); }
}

public class TestDecoratorPattern2 {
    public static void main(String[] args) {
        Student s1 = new KoreanStudent();
        System.out.println(s1.getDescription()); // return Korean

        Science s2 = new Science(s1);
        System.out.println(s2.getDescription()); // return Korean enrolls Science;

        Art s3 = new Art(s2);
        System.out.println(s3.getDescription()); // return Korean enrolls Science enrolls Art
    }
}
반응형

'학습일지 > Language' 카테고리의 다른 글

[Design Pattern] Strategy  (0) 2020.12.24
[Design Pattern] Bridge  (0) 2020.12.23
[Design Pattern] Adapter  (0) 2020.12.18
[Design Pattern] Observer  (0) 2020.12.17
[Design Pattern] Builder  (0) 2020.12.16