Javaのデコレータパターン
1. 概要
デコレータパターンを使用して、静的または動的にオブジェクトに追加の責任を付加できます。デコレータは、元のオブジェクトへの拡張インターフェイスを提供します。
このパターンの実装では、継承よりも合成を優先します。これにより、装飾要素ごとにサブクラス化のオーバーヘッドを何度も減らすことができます。 この設計に関連する再帰は、必要な回数だけオブジェクトを装飾するために使用できます。
2. デコレータパターンの例
クリスマスツリーオブジェクトがあり、それを装飾したいとします。 装飾はオブジェクト自体を変更しません。 クリスマスツリーに加えて、ガーランド、ティンセル、ツリートッパー、バブルライトなどの装飾アイテムを追加しているだけです。
このシナリオでは、元のGang of Fourの設計と命名規則に従います。最初に、ChristmasTreeインターフェイスとその実装を作成します。
public interface ChristmasTree {
String decorate();
}
このインターフェースの実装は次のようになります。
public class ChristmasTreeImpl implements ChristmasTree {
@Override
public String decorate() {
return "Christmas tree";
}
}
次に、このツリーの抽象TreeDecoratorクラスを作成します。 このデコレータは、 ChristmasTree インターフェイスを実装するだけでなく、同じオブジェクトを保持します。 同じインターフェイスから実装されたメソッドは、インターフェイスからdecorate()メソッドを呼び出すだけです。
public abstract class TreeDecorator implements ChristmasTree {
private ChristmasTree tree;
// standard constructors
@Override
public String decorate() {
return tree.decorate();
}
}
次に、装飾要素を作成します。 これらのデコレータは、抽象 TreeDecorator クラスを拡張し、要件に応じてdecorate()メソッドを変更します。
public class BubbleLights extends TreeDecorator {
public BubbleLights(ChristmasTree tree) {
super(tree);
}
public String decorate() {
return super.decorate() + decorateWithBubbleLights();
}
private String decorateWithBubbleLights() {
return " with Bubble Lights";
}
}
この場合、次のことが当てはまります。
@Test
public void whenDecoratorsInjectedAtRuntime_thenConfigSuccess() {
ChristmasTree tree1 = new Garland(new ChristmasTreeImpl());
assertEquals(tree1.decorate(),
"Christmas tree with Garland");
ChristmasTree tree2 = new BubbleLights(
new Garland(new Garland(new ChristmasTreeImpl())));
assertEquals(tree2.decorate(),
"Christmas tree with Garland with Garland with Bubble Lights");
}
最初のtree1オブジェクトでは、1つの Garland のみで装飾しているのに対し、他のtree2オブジェクトは1つので装飾していることに注意してください。 ]BubbleLightsと2つのGarlands。 このパターンにより、実行時に必要な数のデコレータを追加できる柔軟性が得られます。
4. 結論
この記事では、デコレータのデザインパターンを見てみました。 これは、次の場合に適しています。
- オブジェクトの動作や状態を追加、拡張、または削除したい場合
- クラスの単一のオブジェクトの機能を変更し、他のオブジェクトは変更しない場合
この例の完全なソースコードは、GitHubでから入手できます。