mohuneko’s blog

かんばる駆け出しエンジニアのブログです

【Java】Flyweight パターン【デザインパターン】

駆け出しエンジニアがデザインパターンをもくもく勉強します

 こんな本で勉強しています🌟

目次

Flyweightパターンについて

Flyweightパターンとは

  • Flyweightパターンは、インスタンスをできるだけ共有させて、メモリ使用量を軽くするパターンです
    • Flyweightという英単語は、"フライ級"という意味で、ボクシングで最も体重が軽い階級のことです🥊
    • Flyweightパターンにおいての重さとは、メモリ使用量のことです

サンプルプログラム

  • Flyweightパターンを使って、ファイルを読んで、大きな文字(重いインスタンスを作る)を表現するクラスの処理について取り上げます
  • 各クラスの役割は以下のようになっています
名前 役割
BigChar(Flyweight 大きな文字を表すクラス
BigCharFactory(FlyweightFactory) BigCharのインスタンスを共有しながら生成するクラス
BigString(Client) BigCharを集めて作った「大きな文字列」を表すクラス

f:id:mohuNeko:20210102144529p:plain

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クラス

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な情報になります
  • また、管理されているインスタンスは、ガベージコレクションされません

今日のポイント

 本日もお疲れ様です😊