Derocatorパターンとは
オブジェクトに飾り付けをほどこしていく。
Componentの役
機能を追加するときの核になる役。
package decorator;
public abstract class Display {
public abstract int getColumns();
public abstract int getRows();
public abstract String getRowText(int row);
public final void show() {
for (int i = 0; i < getRows(); i++) {
System.out.println(getRowText(i));
}
}
}
ConcreteComponentの役
Component役のインターフェースを実装する役。
package decorator;
/**
* 1行の文字列を表示するクラス
*/
public class StringDisplay extends Display{
private String string;
public StringDisplay(String string) {
this.string = string;
}
@Override
public int getColumns() {
return string.getBytes().length;
}
@Override
public int getRows() {
return 1;
}
@Override
public String getRowText(int row) {
return row == 0 ? string : null;
}
}
Decorator(装飾者)の役
Component役と同じインターフェースを持つ。
また、Decorator役が飾る対象となるComponent役を持つ。
この役は自分が飾る対象を知っている。
package decorator;
/**
* 飾り枠を表すクラス
*/
public abstract class Border extends Display {
// この飾り枠がくるんでいる「中身」をさす
protected Display display;
protected Border(Display display) {
this.display = display;
}
}
ConcreteDecorator(具体的な装飾者)の役
具体的なDecoratorの役。
package decorator;
/**
* 文字列の左右に決まった文字で飾りをつけるクラス
*
*/
public class SideBorder extends Border {
private char borderChar;
protected SideBorder(Display display, char ch) {
super(display);
this.borderChar = ch;
}
@Override
public int getColumns() {
// 文字数は両側に飾り文字分を加えたもの
return 1 + display.getColumns() + 1;
}
@Override
public int getRows() {
return display.getRows();
}
@Override
public String getRowText(int row) {
return borderChar + display.getRowText(row) + borderChar;
}
}
package decorator;
/**
* 上下左右に飾りをつけるクラス
*
*/
public class FullBorder extends Border{
protected FullBorder(Display display) {
super(display);
}
@Override
public int getColumns() {
// 文字数は両側に飾り文字分を加えたもの
return 1 + display.getColumns() + 1;
}
@Override
public int getRows() {
// 文字数は上下に飾り文字分を加えたもの
return 1 + display.getRows() + 1;
}
@Override
public String getRowText(int row) {
if (row == 0) {
// 枠の上側
return "+" + makeLine('-', display.getColumns()) + '+';
} else if (row == display.getRows() + 1) {
// 枠の下側
return "+" + makeLine('-', display.getColumns()) + '+';
} else {
return "|" + display.getRowText(row - 1) + "|";
}
}
/**
* 指定した文字を連続して作成する
*
*/
private String makeLine(char ch, int count) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < count; i++) {
buf.append(ch);
}
return buf.toString();
}
}
呼び出し元
package decorator;
public class Main {
public static void main(String[] args) {
Display d1 = new StringDisplay("Hello world");
Display d2 = new SideBorder(d1, '#');
Display d3 = new FullBorder(d2);
d1.show();
d2.show();
d3.show();
}
}
実行結果
包めば包むほど機能が追加されていく。
その際、包まれる側を変更することなく、機能の追加を行うことができる。
こちらを参考にさせていただきました。
増補改訂版Java言語で学ぶデザインパターン入門