フライウェイトパターン (Flyweight Pattern)

📢 この記事は gemini-3-flash-preview によって翻訳されました

Flyweight Pattern(フライウェイトパターン) オブジェクト構造型パターン

意図

共有技術を使って、大量の細かい粒度のオブジェクトを効率的にサポートするよ。

構造

フライウェイトパターン

役割はこんな感じ:

  • Flyweight:外部状態を受け取り、それに基づいて動作するためのインターフェースを定義するよ。

  • ConcreteFlyweight:Flyweight インターフェースを実装して、内部状態(もしあれば)のためのストレージを追加するんだ。ConcreteFlyweight オブジェクトは共有可能である必要があるよ。保持する状態は「内部的」なもの、つまりオブジェクトが置かれた状況に依存しないものである必要があるんだ。

  • すべての Flyweight サブクラスが共有される必要があるわけじゃないよ。Flyweight インターフェースは共有を可能にするけど、強制はしないんだ。Flyweight オブジェクト構造の特定の階層では、UnsharedConcreteFlyweight オブジェクトが ConcreteFlyweight オブジェクトを子ノードとして持つこともよくあるよ。

  • FlyweightFactory:Flyweight オブジェクトを作成して管理するよ。Flyweight が適切に共有されるように制御して、ユーザーが Flyweight をリクエストした時に、作成済みのインスタンスを提供するか、存在しない場合は新しく作成するんだ。

  • Client:Flyweight への参照を保持して、一つ以上の Flyweight の外部状態を計算したり保存したりするよ。

適用性

Flyweight パターンはこんな時に適しているよ:

  • アプリケーションが大量のオブジェクトを使用している
  • 大量のオブジェクトを使用することで、メモリのコストが非常に高くなっている
  • オブジェクトの状態のほとんどが外部状態にできる
  • オブジェクトの外部状態を取り除けば、比較的少数の共有オブジェクトで、多くのオブジェクトグループを代替できる
  • アプリケーションがオブジェクトの識別(アイデンティティ)に依存していない。Flyweight オブジェクトは共有されるから、概念的に異なるオブジェクトでも、同一性テストで真(true)が返ってくることがあるんだ。

例 1

オンライン囲碁プログラムを開発するとするね。たくさんのプレイヤーがオンラインで対局できるようにしたい。サーバーが1台しかないから、メモリ空間を節約するためにフライウェイトパターンを使って実装してみるよ。クラス図は以下の通り。

フライウェイトパターン-例

 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import java.util.ArrayList;

enum PieceColor {BLACK, WHITE} // 駒の色

class PiecePods{ // 駒の位置
    private int x;
    private int y;

    public PiecePods(int a, int b){
        x = a;
        y = b;
    }

    public int getX(){
        return x;
    }

    public int getY() {
        return y;
    }
}

abstract class Piece{ // 駒の定義
    protected PieceColor m_color; // 色
    protected PiecePods m_pos; // 位置

    public Piece(PieceColor color, PiecePods pos){
        this.m_color = color;
        this.m_pos = pos;
    }

    public abstract void draw();
}

class BlackPiece extends Piece{
    public BlackPiece(PieceColor color, PiecePods pos){
        super(color, pos);
    }

    @Override
    public void draw(){
        System.out.println("黒駒を描画するよ");
    }
}

class WhitePiece extends Piece{
    public WhitePiece(PieceColor color, PiecePods pos){
        super(color, pos);
    }

    @Override
    public void draw(){
        System.out.println("白駒を描画するよ");
    }
}

class PieceBoard{ // 盤上の既にある駒
    private static final ArrayList<Piece> m_arrayPiece = new ArrayList<>();
    private String m_blackName; // 黒のプレイヤー名
    private String m_whiteName; // 白のプレイヤー名

    public PieceBoard(String black, String white){
        m_blackName = black;
        m_whiteName = white;
    }

    // 一手打つ、盤上に駒を置く
    public void setPiece(PieceColor color, PiecePods pos){
        Piece piece = null;

        if(color == PieceColor.BLACK){ // 黒を置く
            piece = new BlackPiece(color, pos);
            System.out.println(m_blackName + pos.getX() + pos.getY());
            piece.draw();
        }else{ // 白を置く
            piece = new WhitePiece(color, pos);
            System.out.println(m_whiteName + pos.getX() + pos.getY());
            piece.draw();
        }
        m_arrayPiece.add(piece);
    }
}

例 2

五目並べ

 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class FlyWeightPattern {
    public static void main(String[] args) {
        PieceFactory factory = new PieceFactory();

        Piece wp1 = factory.getPiece(0);
        wp1.draw(2023, 0527);
    }
}

class PieceFactory{
    private Piece[] pieces = {new WhitePiece(), new BlackPiece()};

    public Piece getPiece(int key){
        if(key == 0) return pieces[0];
        else return pieces[1];
    }
}

abstract class Piece{
    protected String color;

    public abstract void draw(int x, int y);
}

class WhitePiece extends Piece{
    public WhitePiece(){
        this.color = "white";
    }

    @Override
    public void draw(int x, int y){
        System.out.println("draw a " + this.color + " piece x: " + x + " y: " + y);
    }
}

class BlackPiece extends Piece{
    public BlackPiece(){
        this.color = "Black";
    }

    @Override
    public void draw(int x, int y){
        System.out.println("draw a " + this.color + " piece x: " + x + " y: " + y);
    }
}

例 3

 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class FlyWeightPattern {
    public static void main(String[] args) {
        ShapeFactory sf = new ShapeFactory();

        Random r = new Random();
        String[] colors = {"red", "blue", "green", "white", "black"};

        for (int i = 0; i < 10; i++) {
            int x = r.nextInt(colors.length);
            Shape s = sf.getShape(colors[x]);
            s.draw(r.nextInt(2023), r.nextInt(527));
        }
    }
}

class ShapeFactory{
    private Map<String, Shape> map = new HashMap<>();

    public Shape getShape(String key){
        if (!map.containsKey(key)) {
            map.put(key, new Circle(key));
            System.out.println("create new circle, color: " + key);
        }
        return map.get(key);
    }
}

abstract class Shape{
    protected String color;

    public abstract void draw(int x, int y);
}

class Circle extends Shape{
    public Circle(String color){
        this.color = color;
    }

    @Override
    public void draw(int x, int y) {
        System.out.println("draw a " + this.color + " circle x: " + x + " y: " + y);
    }
}

Visits Since 2025-02-28

Hugo で構築されています。 | テーマ StackJimmy によって設計されています。