mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-05-14 12:58:37 +00:00
4da36e7826
* Add image and README Signed-off-by: Shogo Hida <shogo.hida@gmail.com> * Add Japanese translation Signed-off-by: Shogo Hida <shogo.hida@gmail.com> * Move image Signed-off-by: Shogo Hida <shogo.hida@gmail.com> Signed-off-by: Shogo Hida <shogo.hida@gmail.com>
7.1 KiB
7.1 KiB
title, category, language, tag
| title | category | language | tag | ||
|---|---|---|---|---|---|
| Decorator | Structural | ja |
|
別名
Wrapper
目的
オブジェクトに責任を動的に追加する。 Decorator パターンは、サブクラス化よりも柔軟な機能拡張方法を提供する。
説明
実世界の例
近くの丘に住む怒ったトロールがいる。大抵は素手だが、たまに武器を持っている。トロールに武器を持たせるためには、新しいトロールを作る必要はなく、適切な武器を動的に装飾すればいい。
分かりやすい説明
Decorator パターンを用いると、decorator クラスのオブジェクトにラップすることで、オブジェクトの振る舞いを実行時間で動的に変更することができる。
Wikipedia の説明
オブジェクト指向プログラミングにおいて、Decorator パターンは、同じクラスの別のオブジェクトの振る舞いに影響を与えることなく、静的もしくは動的に、個別のオブジェクトに振る舞いを加えることができるデザインパターンである。Decorator パターンは、単一責任の原則を遵守するためにしばしば便利である。なぜなら、クラスの機能性を変更せずに拡張することで、開放/閉鎖原則などの関心事の特異な分野を元に、クラスの間で機能性を分割することができるためである。
サンプルコード
トロールを例として使用する。まず、Troll のインターフェイスを実装する SimpleTroll クラスを作る。
public interface Troll {
void attack();
int getAttackPower();
void fleeBattle();
}
@Slf4j
public class SimpleTroll implements Troll {
@Override
public void attack() {
LOGGER.info("The troll tries to grab you!");
}
@Override
public int getAttackPower() {
return 10;
}
@Override
public void fleeBattle() {
LOGGER.info("The troll shrieks in horror and runs away!");
}
}
次に、トロールに対してこん棒を追加する。decorator を使い、動的に追加することが可能である。
@Slf4j
public class ClubbedTroll implements Troll {
private final Troll decorated;
public ClubbedTroll(Troll decorated) {
this.decorated = decorated;
}
@Override
public void attack() {
decorated.attack();
LOGGER.info("The troll swings at you with a club!");
}
@Override
public int getAttackPower() {
return decorated.getAttackPower() + 10;
}
@Override
public void fleeBattle() {
decorated.fleeBattle();
}
}
以下がトロールの動き。
// simple troll
LOGGER.info("A simple looking troll approaches.");
var troll = new SimpleTroll();
troll.attack();
troll.fleeBattle();
LOGGER.info("Simple troll power: {}.\n", troll.getAttackPower());
// change the behavior of the simple troll by adding a decorator
LOGGER.info("A troll with huge club surprises you.");
var clubbedTroll = new ClubbedTroll(troll);
clubbedTroll.attack();
clubbedTroll.fleeBattle();
LOGGER.info("Clubbed troll power: {}.\n", clubbedTroll.getAttackPower());
アウトプット
A simple looking troll approaches.
The troll tries to grab you!
The troll shrieks in horror and runs away!
Simple troll power: 10.
A troll with huge club surprises you.
The troll tries to grab you!
The troll swings at you with a club!
The troll shrieks in horror and runs away!
Clubbed troll power: 20.
クラス図
適用可能性
次のような場合に Decorator パターンを利用する。
- 個々のオブジェクトに責任を動的、かつ透明に(すなわち、他のオブジェクトに影響を与えないように)追加する場合。
- 責任を取りはずすことができるようにする場合。
- サブクラス化による拡張が非現実的な場合。非常に多くの独立した拡張が起こり得ることがある。このような場合、サブクラス化により全ての組み合わせの拡張に対応しようとすると、莫大な数のサブクラスが必要になるだろう。また、クラス定義が隠蔽されている場合や入手できない場合にも、このパターンを利用できる。
チュートリアル
使用例
- java.io.InputStream, java.io.OutputStream, java.io.Reader and java.io.Writer
- java.util.Collections#synchronizedXXX()
- java.util.Collections#unmodifiableXXX()
- java.util.Collections#checkedXXX()
