Javaのフライウェイトパターン
1. 概要
この記事では、フライウェイトのデザインパターンを見ていきます。 このパターンは、メモリフットプリントを削減するために使用されます。 また、オブジェクトのインスタンス化が高価なアプリケーションのパフォーマンスを向上させることもできます。
簡単に言えば、フライウェイトパターンは、作成されたオブジェクトを作成後に保存することでリサイクルするファクトリーに基づいています。 オブジェクトが要求されるたびに、ファクトリはオブジェクトがすでに作成されているかどうかを確認するためにオブジェクトを検索します。 存在する場合は、既存のオブジェクトが返されます。存在しない場合は、新しいオブジェクトが作成され、保存されてから返されます。
フライウェイトオブジェクトの状態は、他の同様のオブジェクトと共有される不変コンポーネント(intrinsic)と、クライアントコードで操作できるバリアントコンポーネント(extrinsic)で構成されます。
フライ級オブジェクトが不変であることが非常に重要です。状態に対するすべての操作は、工場で実行する必要があります。
2. 実装
パターンの主な要素は次のとおりです。
-
クライアントコードがflyweightオブジェクトに対して実行できる操作を定義するインターフェイス
-
インターフェースの1つ以上の具体的な実装
-
オブジェクトのインスタンス化とキャッシュを処理するファクトリ
各コンポーネントを実装する方法を見てみましょう。
2.1. 車両インターフェース
まず、Vehicleインターフェースを作成します。 このインターフェイスはファクトリメソッドの戻り値型になるため、関連するすべてのメソッドを公開する必要があります。
public void start();
public void stop();
public Color getColor();
2.2. コンクリート車両
次に、Carクラスを具象Vehicle.として作成しましょう。私たちの車は、車両インターフェースのすべてのメソッドを実装します。 状態については、エンジンとカラーフィールドがあります。
private Engine engine;
private Color color;
2.3. 車両工場
最後になりましたが、VehicleFactoryを作成します。 新しい車両の製造は非常に費用がかかるため、工場は色ごとに1台の車両のみを作成します。
そのために、マップを単純なキャッシュとして使用して、作成された車両を追跡します。
private static Map vehiclesCache
= new HashMap<>();
public static Vehicle createVehicle(Color color) {
Vehicle newVehicle = vehiclesCache.computeIfAbsent(color, newColor -> {
Engine newEngine = new Engine();
return new Car(newEngine, newColor);
});
return newVehicle;
}
クライアントコードがオブジェクトの外部状態(車両の色)にのみ影響を与え、createVehicleメソッドに引数として渡すことに注意してください。
3. ユースケース
3.1. データ圧縮
フライウェイトパターンの目標は、できるだけ多くのデータを共有することでメモリ使用量を削減することです。したがって、ロスレス圧縮アルゴリズムの優れた基盤となります。 この場合、各flyweightオブジェクトはポインターとして機能し、その外部状態はコンテキスト依存情報です。
この使用法の典型的な例は、ワープロです。 ここで、各キャラクターは、レンダリングに必要なデータを共有するフライウェイトオブジェクトです。 その結果、ドキュメント内の文字の位置のみが追加のメモリを占有します。
3.2. データキャッシング
最近の多くのアプリケーションは、キャッシュを使用して応答時間を改善しています。 フライウェイトパターンはキャッシュのコアコンセプトに似ており、この目的によく適合します。
もちろん、このパターンと一般的な汎用キャッシュとの間には、複雑さと実装にいくつかの重要な違いがあります。
4. 結論
要約すると、このクイックチュートリアルでは、Javaのフライウェイトデザインパターンに焦点を当てました。 また、パターンに関連する最も一般的なシナリオのいくつかをチェックアウトしました。
例のすべてのコードは、the GitHub projectで利用できます。