Flyweight パターン (多数のオブジェクトの中で同じものと見なせるオブジェクトを共有し, オブジェクトの構築のための負荷を減らす)

[Flyweight] という英単語は, [フライ級] を意味する.

このパターンは, 生成済みのオブジェクトをできるだけ再利用 (共有) し, 無駄なオブジェクト生成 (メモリ使用) を防止する仕組みを提供するパターン.

このパターンを適用するかどうかの判断基準の1つとしては, 軽量化対象のクラスが, 不変なクラス (イミュータブル, immutable なクラス) かどうかということがあげられる. つまり, 軽量化対象が不変でないクラスの場合は, その状態が変更されている場合に再利用できないのでこのパターンに適しない. 不変なクラスとはオブジェクトが生成れた後にそのオブジェクトの状態が変化しない (フィールド値が不変) ようなクラスのことを言う.

役割

  1. Flyweight (フライ級):
通常の利用方法だと, 多くのオブジェクト (無駄なオブジェクト) を生成され得る可能性のあるクラス.
  1. FlyweightFactory (フライ級の工場):
[Flyweight] を生成管理する工場. [Flyweight] のオブジェクトが必要な場合は, この工場経由で取得する. 生成した [Flyweight] オブジェクトをプールし, 共有 可能なオブジェクトが要求された場合は, プールからそのオブジェクトを返す. [Flyweight] を管理するファクトリークラスが複数存在すると, 再利用できる [Flyweight] を別個に管理 (同種の [Flyweight] を複数生成してしまう) してしまう ため, [Singleton] パターンを適用する.
  1. Client (利用者):
[Flyweight] パターンを適用したクラスを利用し処理する.

クラス図

Flyweight パターンのクラス図

_images/designpattern-flyweight011.gif

ソースコード

  1. Flyweight.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public class Flyweight{
    private int id;
    private int counter;

    public Flyweight(int id){
	this.id = id;
	System.out.println("Flyweight オブジェクト生成: id = ["+id+"]");
    }

    private int flyweightMethod1(){
	return ++counter;
    }

    public void flyweightMethod2(){
	System.out.println("Flyweight-fM2(): id = [" + id + "]/counter = [" + flyweightMethod1() + "]");
    }
}
  1. FlyweightFactory.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import java.util.Map;
import java.util.HashMap;

public class FlyweightFactory{
    private static FlyweightFactory singleton = new FlyweightFactory();
    private Map<Integer, Flyweight> pool = new HashMap<Integer, Flyweight>();
    private FlyweightFactory(){}
    public static FlyweightFactory getInstance(){
	return singleton;
    }

    /*
      マルチスレッドを考慮し, [synchronized] 修飾子を付け, 同期化させる.
      同期化させておかないと, 無駄なオブジェクトを生成してしまう可能性が
      あるためである.
    */
    public synchronized Flyweight getFlyweight(int id){
	Flyweight flyweight = (Flyweight)pool.get(id);
	
	if(flyweight == null){
	    flyweight = new Flyweight(id);
	    pool.put(id, flyweight);
	}
	return flyweight;
    }
}
  1. Client.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class Client{
    public static void main(String[] args){
	FlyweightFactory factory = FlyweightFactory.getInstance();
	int[] number = new int[]{0, 1, 2, 1, 3, 4, 2, 2, 3};
	for(int i = 0; i < number.length; i++){
	    Flyweight flyweight = factory.getFlyweight(number[i]);
	    flyweight.flyweightMethod2();
	}
    }
}

上記のプログラムの実行結果:

[wtopia Flyweight]$ java Client
Flyweight オブジェクト生成: id = [0]
Flyweight-fM2(): id = [0]/counter = [1]
Flyweight オブジェクト生成: id = [1]
Flyweight-fM2(): id = [1]/counter = [1]
Flyweight オブジェクト生成: id = [2]
Flyweight-fM2(): id = [2]/counter = [1]
Flyweight-fM2(): id = [1]/counter = [2]
Flyweight オブジェクト生成: id = [3]
Flyweight-fM2(): id = [3]/counter = [1]
Flyweight オブジェクト生成: id = [4]
Flyweight-fM2(): id = [4]/counter = [1]
Flyweight-fM2(): id = [2]/counter = [2]
Flyweight-fM2(): id = [2]/counter = [3]
Flyweight-fM2(): id = [3]/counter = [2]