Flyweight パターン

Flyweightパターンは、GoF(Gang of Four)によって定義されたデザインパターンの一つです。このパターンは、同じ性質を持つオブジェクトのインスタンスを複数作成する代わりに、単一のインスタンスを共有することで、メモリ使用量と計算コストを削減することを目的としています。Flyweightという名前は、ボクシングの階級の一つである「フライ級」に由来しており、軽量なオブジェクトを意味しています。

Flyweightパターンの構造



Flyweightパターンでは、主に以下の要素が関係します。

Flyweight: 共有されるオブジェクトのインターフェースを定義します。このインターフェースを通じて、共有オブジェクトの操作を行います。
ConcreteFlyweight: Flyweightインターフェースを実装した具体的なクラスです。このクラスのインスタンスは共有されます。
UnsharedConcreteFlyweight: Flyweightインターフェースを実装していますが、共有されないクラスです。必要な場合のみ使用されます。
FlyweightFactory: Flyweightオブジェクトの生成と管理を行います。クライアントからの要求に応じて、既存のオブジェクトを返すか、新しいオブジェクトを生成します。

Flyweightパターンの動作



Flyweightパターンを採用したAPIでは、クライアントはFlyweightクラスのインスタンスを直接作成する代わりに、FlyweightFactoryの`getFlyweight()`メソッドを使用します。`FlyweightFactory`は、以下の手順でオブジェクトを返します。

1. インスタンスが存在しない場合:
新しいFlyweightインスタンスを生成します。
生成したインスタンスを内部のプールに保存します。
生成したインスタンスを返します。
2. インスタンスが既に存在する場合:
プールから既存のFlyweightインスタンスを取得します。
取得したインスタンスを返します。

このように`FlyweightFactory`は内部で異なる処理を実行しますが、クライアントは常に同じ結果を得られます。このため、クライアントは`FlyweightFactory`の内部構造を意識せずに利用できます。

Flyweightパターンの適用例



Flyweightパターンが特に有効なのは、不変な(イミュータブル)オブジェクトを扱う場合です。不変なオブジェクトは生成後に状態が変化しないため、複数の箇所で同じインスタンスを共有しても問題ありません。Javaでは`java.math.BigInteger`や`java.awt.Color`などが不変なクラスの例として挙げられます。

Javaでの利用例



以下に、JavaでFlyweightパターンを実装した例を示します。

java
// Flyweightインターフェース
interface Stamp {
void print(String text);
}

// ConcreteFlyweightクラス
class ConcreteStamp implements Stamp {
private String value;

public ConcreteStamp(String value) {
this.value = value;
}

@Override
public void print(String text) {
System.out.print(value);
}
}

// FlyweightFactoryクラス
class StampFactory {
private static Map stamps = new HashMap<>();

public static Stamp get(String value) {
if (!stamps.containsKey(value)) {
stamps.put(value, new ConcreteStamp(value));
}
return stamps.get(value);
}
}

// 利用例
public class FlyweightTest {
public static void main(String[] args) {
StampFactory.get("た").print("a");
StampFactory.get("か").print("b");
StampFactory.get("い").print("c");
StampFactory.get("た").print("d");
StampFactory.get("け").print("e");
StampFactory.get("た").print("f");
StampFactory.get("て").print("g");
StampFactory.get("か").print("h");
StampFactory.get("け").print("i");
StampFactory.get("た").print("j");
}
}


このコードを実行すると、「たかいたけたてかけた」と出力されます。`FlyweightTest.main()`では`StampFactory.get()`を10回呼び出していますが、実際に生成されたインスタンスは5つ(「た」、「か」、「い」、「け」、「て」)のみであり、インスタンスが共有されていることが分かります。

注意点



`FlyweightFactory`に一度保存されたインスタンスは、不要になったとしてもガベージコレクションの対象になりません。そのため、状況に応じて`FlyweightFactory`から明示的に削除する必要があります。

関連するパターン



Singletonパターン: `FlyweightFactory`はSingletonパターンとして実装されることが多いです。これにより、`FlyweightFactory`のインスタンスが一つだけになるため、オブジェクトの管理を効率的に行えます。

関連項目



デザインパターン (ソフトウェア)
ガベージコレクション
イミュータブル

外部リンク



Javaの理論と実践: 可変性か、不変性か? | IBM, Internet Archive

もう一度検索

【記事の利用について】

タイトルと記事文章は、記事のあるページにリンクを張っていただければ、無料で利用できます。
※画像は、利用できませんのでご注意ください。

【リンクついて】

リンクフリーです。