【Java】Flyweight パターン【デザインパターン】
目次
Flyweightパターンについて
Flyweightパターンとは
サンプルプログラム
名前 | 役割 |
---|---|
BigChar(Flyweight) | 大きな文字を表すクラス |
BigCharFactory(FlyweightFactory) | BigCharのインスタンスを共有しながら生成するクラス |
BigString(Client) | BigCharを集めて作った「大きな文字列」を表すクラス |
BigCharクラス
- コンストラクタで、引数で与えられた文字の大きな文字を作成します
- 文字列は、fontdataフィールドに格納します
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class BigChar { // 文字の名前 private char charname; // 大きな文字を表現する文字列('#' '.' '\n'の列) private String fontdata; // コンストラクタ public BigChar(char charname) { this.charname = charname; try { BufferedReader reader = new BufferedReader( new FileReader("big" + charname + ".txt") ); String line; StringBuffer buf = new StringBuffer(); while ((line = reader.readLine()) != null) { buf.append(line); buf.append("\n"); } reader.close(); this.fontdata = buf.toString(); } catch (IOException e) { this.fontdata = charname + "?"; } } // 大きな文字を表示する public void print() { System.out.print(fontdata); } }
BigCharFactoryクラス
- BigCharのインスタンスを作成する工場です
- poolフィールドでこれまでにつくったBigCharのインスタンスを管理しています
- HashMp<で文字とインスタンスの対応関係を管理します
- BigCharFactoryのインスタンスは一個だけでいいので、Singletonパターンで実現します
- getInstanceでBigCharFactoryのインスタンスを得ます
- getBigCharメソッドで、引数に与えられた文字に対応するBigCharのインスタンスを作成します
- すでに同じ文字に対応するインスタンスが生成されていたら、新しいインスタンスを作らず、以前のインスタンスを返します
import java.util.HashMap; public class BigCharFactory { // すでに作ったBigCharのインスタンスを管理 private HashMap pool = new HashMap(); // Singletonパターン private static BigCharFactory singleton = new BigCharFactory(); // コンストラクタ private BigCharFactory() { } // 唯一のインスタンスを得る public static BigCharFactory getInstance() { return singleton; } // BigCharのインスタンス生成(共有) public synchronized BigChar getBigChar(char charname) { BigChar bc = (BigChar)pool.get("" + charname); //文字に対応するいインスタンスがあるか確認 if (bc == null) { bc = new BigChar(charname); // ここでBigCharのインスタンスを生成 pool.put("" + charname, bc); //poolに登録 } return bc; } }
BigStringクラス
- BigCharを集めて作った「大きな文字列」を表すクラスです
- 新しくインスタンスをnewするのではなく、
bigchars[i] = factory.getBigChar(string.charAt(i))
で、インスタンスを保持しています - BigCharFactoryを使うことで、同じ文字でできるBigCharのインスタンスを共有します
- 例えば、1212123というBigCharsの場合、1,2,3のBigCharインスタンスを共有して、使いまわします
public class BigString { // 「大きな文字」の配列 private BigChar[] bigchars; // コンストラクタ public BigString(String string) { bigchars = new BigChar[string.length()]; BigCharFactory factory = BigCharFactory.getInstance(); for (int i = 0; i < bigchars.length; i++) { bigchars[i] = factory.getBigChar(string.charAt(i)); } } // 表示 public void print() { for (int i = 0; i < bigchars.length; i++) { bigchars[i].print(); } } }
Mainクラスで動作確認
- 引数で与えられた文字列を元に、BigStringのインスタンスを作り、表示します
public class Main { public static void main(String[] args) { if (args.length == 0) { System.out.println("Usage: java Main digits"); System.out.println("Example: java Main 1212123"); System.exit(0); } BigString bs = new BigString(args[0]); bs.print(); } }
Flyweightパターンのメリット
- インスタンスを共有すると、毎回newする必要がなく、メモリ使用量が少なくなります。
- 一般的に言えば、インスタンスを共有すると、インスタンスを生成するのに必要なリソースの量を減らすことができます。
- 時間もリソースの一種になります。Flyweightパターンを使ってインスタンスを共有すれば、インスタンスをnewする数を減らすことができるので、プログラムのスピードを上げることができます。
Flyweightパターンの特徴
- 共有しているインスタンスを変更すると、それを使っている箇所全部に影響が及ぶので、共有すべき情報と、共有しない情報を区別する必要があります
- 共有させる情報を、intrindicな情報と言います
- どんな状況下でも、変わることのない情報や、状態に依存しない情報です
- BigChar のフォントデータは変わることがないので、intrinsicな情報です
- 共有すべきでない情報を、extrinsicな情報と言います
- 状況によって変化する情報、状態依存する情報です
- BigCharのインスタンスが、BigStringの何番目か、という情報は extrinsicな情報になります
- また、管理されているインスタンスは、ガベージコレクションされません
今日のポイント
- Flyweightパターンは、インスタンスをできるだけ共有させて、メモリ使用量を軽くするパターンです。
- インスタンスを共有すると、インスタンスを生成するのに必要なリソースの量を減らすことができます。
- 共有しているインスタンスを変更すると、複数箇所に影響が及ぶので、共有すべきintrindicな情報と、共有しないextrinsicな情報を区別する必要があります
- 管理されているインスタンスは、ガベージコレクションされません
本日もお疲れ様です😊