학습일지/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
}
}
반응형