= Decorator Pattern =
장식과 내용물을 동일시해서 장식을 여러 겹 중복되게 하기. 투과적인 인터페이스(API)를 갖는다. (예를 들어 케이크에 초콜릿으로 코팅하면 초콜릿 케이크, 생크림으로 코팅하면 생크림 케이크)
* 장식이 되는 기능을 하나씩 추가하면서 좀 더 목적에 맞는 객체 만들기
* 기능 확장이 필요할 때 서브클래싱 대신 쓸 수 있는 유연한 대안 [(https://ko.wikipedia.org/wiki/%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0_%ED%8C%A8%ED%84%B4)]
* [[Composite Pattern]]과 무엇이 다른가?
* "Decorator Pattern은 테두리 장식을 중복해서 **__기능을 추가__**"하는 것에 집중. 이 때, 내용물을 변경하지 않고 기능을 추가할 수 있다.
* 예시
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("text.txt")))
{{tag>Architecture Modeling Design_Pattern Structural}}
= Component =
package component;
import java.util.stream.IntStream;
public abstract class Display {
public abstract int getColumns();
public abstract int getRows();
public abstract String getRowText(int row);
public final void show() {
IntStream.range(0, getRows()).forEach(row -> System.out.println(getRowText(row)));
}
}
== ConcreteComponent ==
package component;
public class StringDisplay extends Display {
private String str;
public StringDisplay(String str) {
this.str = str;
}
@Override
public int getColumns() {
return str.getBytes().length;
}
@Override
public int getRows() {
return 1;
}
@Override
public String getRowText(int row) {
return row == 0? str : null;
}
}
== Decorator ==
package decorator;
import component.Display;
public abstract class Border extends Display {
protected Display display; // 내용물
public Border(Display display) {
this.display = display;
}
}
=== ConcreteDecorator ===
package decorator;
public class SideBorder extends Border {
private char borderDecorator;
public SideBorder(Display display, char borderDecorator) {
super(display);
this.borderDecorator = borderDecorator;
}
@Override
public int getColumns() {
return display.getColumns() + 2; // 양쪽 장식물 길이 더한 값
}
@Override
public int getRows() {
return display.getRows();
}
@Override
public String getRowText(int row) {
StringBuilder sb = new StringBuilder();
sb.append(borderDecorator);
sb.append(display.getRowText(row));
sb.append(borderDecorator);
return sb.toString();
}
}
package decorator;
import java.util.stream.IntStream;
import component.Display;
public class FullBorder extends Border {
public FullBorder(Display display) {
super(display);
}
@Override
public int getColumns() {
return display.getColumns() + 2; // 양쪽 장식물 길이 더한 값
}
@Override
public int getRows() {
return display.getRows() + 2; // 상하 장식물 길이 더한 값
}
@Override
public String getRowText(int row) {
StringBuilder sb = new StringBuilder();
// 상하 사이인 경우
if(0 < row && row < display.getRows() + 1) {
sb.append('|');
sb.append(display.getRowText(row - 1));
sb.append('|');
}
else {
sb.append('+');
IntStream.range(0, display.getColumns()).forEach(i -> sb.append('-'));
sb.append('+');
}
return sb.toString();
}
}
= Client =
import component.Display;
import component.StringDisplay;
import decorator.FullBorder;
import decorator.SideBorder;
public class Main {
public static void main(String[] args) {
Display component = new StringDisplay("Hello world");
Display decorator1 = new SideBorder(component, '#');
Display decorator2 = new FullBorder(decorator1);
component.show();
decorator1.show();
decorator2.show();
System.out.println();
Display composite = new SideBorder(
new FullBorder(
new FullBorder(
new SideBorder(
new FullBorder(
new StringDisplay("Hello world")
) , '*')))
, '/');
composite.show();
}
}
/*
Hello world
#Hello world#
+-------------+
|#Hello world#|
+-------------+
/+-----------------+/
/|+---------------+|/
/||*+-----------+*||/
/||*|Hello world|*||/
/||*+-----------+*||/
/|+---------------+|/
/+-----------------+/
*/