6

flyweight パターンの実装を探していましたが、Google 検索の 20 ページに到達した後、あきらめました。無数のばかげた例がありますが、Java で再利用可能な実装を公開した人は誰もいないようです。

私にとって、flyweight は、そのようなインスタンスを多数保持する必要がある場合にのみ意味があるためコレクションとして実装する必要があります。私が望むのは、バイト/ショート/整数/ロングマッパーの実装を取り、通常のオブジェクトコレクションのように見えるリスト、セット、またはマップのいずれかを返すファクトリですが、そのデータはプリミティブの配列として内部的に保存されます。多くのラムを節約します。マッパーは X 型のオブジェクトを受け取り、それをプリミティブにマップするか、その逆を行います。

そのようなものはどこかにありますか?

[編集]何百もの例があるだけでなく、このパターンをサポートするコレクションライブラリを探しています。

4

6 に答える 6

3

List を置き換えたい場合は、代わりに TByteArrayList を使用できます。List where MyClass { int a; を置き換えたい場合 T オブジェクト。代わりに TIntObjectHashMap を使用できます。

順序付けが必要な 2 つのフィールドまたは 3 つ以上のフィールドで何かを置き換えたい場合は、配列をラップしてデータを保持する独自のクラスを実装する必要があります。これは、列ベースのテーブル モデルを使用しています。

例えば

class MyClass {
    byte b;
    int i;
    String s;
}

class MyClassList {
    int size = 0;
    int capacity;
    byte[] bytes;
    int[] ints;
    String[] strings;

    MyClassList(int capacity) {
        this.capacity = capacity;
    }

    public void add(MyClass myClass) {
        if (size == capacity) resize();
        bytes[size] = myClass.b;
        ints[size] = myClass.i;
        strings[size] = myClass.s;
        size++;
    }

    public void get(MyClass myClass, int index) {
        if (index > size) throw new IndexOutOfBoundsException();
        myClass.b = bytes[index]; 
        myClass.i = ints[index];
        myClass.s = strings[index];
    }
}

Java 5.0 以降、自動ボクシング キャッシュは flyweights の例です。

Integer i1 = 1;
Integer i2 = 1;
System.out.println(i1 == i2); // true, they are the same object.

Integer i3 = -200;
Integer i4 = -200;
System.out.println(i3 == i4); // false, they are not the same object.

コードを読みたい場合は、IDE の Integer.valueOf(int) または http://www.docjar.com/html/api/java/lang/Integer.java.html行 638を見てください。

編集: 整数のオートボクシングは、コレクションである IntegerCache を使用します。ArrayList は、配列をラップし、サイズを持つクラスです...

private static class IntegerCache {
    static final int high;
    static final Integer cache[];
于 2011-07-27T08:35:22.723 に答える
2

私は、 Integer.valueOf(String s) はかなりフライ級だと思います。私の知る限り、作成された整数の一部が内部的に保持されるため、以前に渡した文字列を渡すと、既存のインスタンスが返されます。

于 2011-07-27T08:34:47.930 に答える
1

あなたの要件については、TroveまたはColtを試す必要があると思います。これらのライブラリは、プリミティブ コレクションをサポートしています。

于 2011-07-27T08:13:27.177 に答える
1

Gang of Four -- Design Patterns を見たことがありますか? 必要に応じて、(C++ ではありますが) 彼らの実装を書き直しますが、少し後になります。

これはあなたが持つべき本の 1 つで、いつ役に立つかわかりません。

于 2011-07-27T07:55:13.257 に答える
1

GNU Troveはパッケージでそのようなことを行いgnu.trove.decoratorます (List ではなく Map と Set のみ)。

この種のことは非常に非効率的ですが、トレードオフに値する状況が多くあるとは思えません。

適切なプリミティブ コレクションを使用しないのはなぜですか?

于 2011-07-27T08:16:13.807 に答える
0

Flyweight が Java でどの程度うまく機能するかを確認するためのテスト プログラムを作成しました。記録のために、ここで私の結果を説明します。YMMV

1) オブジェクトに複数のフィールドがある場合は、単一の int または long でそれらをマッシュアップすることで、CPU を節約できます。これはプログラミングが面倒でエラーが発生しやすいですが、複数の配列アクセスはビット操作よりもコストがかかるため、数パーセント高速です。フィールドの数が増えるほど、なおさらです。

2) 小さなインスタンス (状態の 4 バイト) の場合、インスタンスを直接保存する場合よりも約 25% 遅くなります。ただし、get ごとに新しいインスタンスを作成しない場合のみ。これが本当の問題です。get のたびに新しいインスタンスを作成する必要があると、非常にコストがかかります。その場合、25% 遅くなるのではなく、500% 遅くなります!

3) get でインスタンスの作成を保存する方法が 2 つあります。

A) get メソッドは、新しいインスタンスを作成するのではなく、既存のインスタンスを埋めます。つまり、結果オブジェクトを入力として get メソッドに渡します。

B) 不変のインスタンスを使用してキャッシュし、get からキャッシュされたインスタンスを返す。これは、リスト インデックスが重要であり、リスト内で同じ値を何度も再利用することが予想される場合にのみ役立ちます。これを行う場合は、何らかの状態ではなく、キャッシュされたインスタンスへの参照をコレクションに直接保存することもできます。これは、とにかく参照に対してインスタンスごとに 4 バイトしか支払わないためです。その場合、参照の代わりに状態を格納する意味を成すには、状態が 2 バイト以下である必要があります。

したがって、最終的な答えとして、Flyweight 用の汎用ライブラリが存在しない理由は、特定の条件下でのみ料金が発生するためです。

于 2011-07-27T19:52:55.753 に答える