Существует ли какая-либо реализация шаблонов Java flyweight?

Я искал легкую реализацию шаблона и сдался после достижения страницы 20 поиска Google. Хотя существует бесчисленное множество глупых примеров, кажется, что никто и никогда не публиковал повторно используемую реализацию на Java.

Для меня flyweight действительно имеет смысл, только если вам нужно хранить много таких экземпляров, поэтому он должен быть реализован как коллекция. То, что я хотел бы, это Фабрика, которая принимает реализацию mapper byte/short/int/long и возвращает либо List, Set, либо Map, которая выглядит как обычная коллекция Object, но хранит свои данные внутри себя как массив примитивов, тем самым экономя много барана. Картограф будет брать объект типа X и отображать его на примитив, или делать это наоборот.

Есть ли что-то подобное в продаже?

[EDIT] Я ищу библиотеку Collection, которая поддерживает этот шаблон, а не просто какой-либо пример, которых сотни.

6 ответов

Решение

Если вы хотите заменить List, вы можете использовать TByteArrayList. Если вы хотите заменить List, где MyClass { int a; Т объект; } вместо этого вы можете использовать TIntObjectHashMap.

Если вы хотите заменить что-то двумя полями, которые должны быть упорядочены, или тремя или более полями, вам нужно реализовать свой собственный класс, который упаковывает массивы для хранения данных. Это использует модель таблицы на основе столбцов.

например

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, кеши автобокса являются примерами весов.

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.

Если вы хотите прочитать код, взгляните на Integer.valueOf(int) в вашей IDE или http://www.docjar.com/html/api/java/lang/Integer.java.html строка 638.

РЕДАКТИРОВАТЬ: Autoboxing для Integer использует IntegerCache, который является коллекцией. ArrayList - это класс, который упаковывает массив и имеет размер...

private static class IntegerCache {
    static final int high;
    static final Integer cache[];

Я думаю, что Integer.valueOf(String s) довольно легкий вес. Потому что, насколько я знаю, он хранит некоторое количество созданных целых чисел внутри, поэтому, когда вы передаете строку, которую вы передали ранее, - он возвращает вам существующий экземпляр.

GNU Trove делает что-то подобное с gnu.trove.decorator пакет (только карта и набор, а не список).

Подобные вещи довольно неэффективны, хотя я сомневаюсь, что во многих ситуациях компромисс стоит того.

Почему бы просто не использовать соответствующие примитивные коллекции?

Для вашего требования, я думаю, вы должны попробовать Trove или Colt. Эти библиотеки поддерживают примитивные коллекции.

Вы видели "Банду четырех"? Я перепишу их реализацию (хотя и в C++), если хотите, но чуть позже.

Это одна из тех книг, которые вы должны иметь - никогда не знаете, когда она может пригодиться.

Я сделал тестовую программу, чтобы увидеть, насколько хорошо Flyweight будет работать в Java. Для протокола, я опишу свои результаты здесь. YMMV

1) Если у вас есть несколько полей в ваших объектах, вы сэкономите некоторый процессор, смешав их в одном int или long. Это боль в программировании и подвержена ошибкам, но это на несколько процентов быстрее, потому что доступ к нескольким массивам обходится дороже, чем битовые манипуляции. Тем более что количество полей растет.

2) Для небольших экземпляров (4 байта состояния) он будет работать примерно на 25% медленнее, чем непосредственное хранение экземпляра. Но ТОЛЬКО если вы не создаете новый экземпляр при каждом получении. Вот где настоящая проблема. Необходимость создавать новый экземпляр для каждого экземпляра очень дорога; в этом случае это не на 25% медленнее, а на 500% медленнее!

3) я вижу два способа сохранить создание экземпляра на get:

A) Ваш метод get заполняет уже существующий экземпляр, а не создает новый. Другими словами, вы передаете объект результата как входные данные для вашего метода get.

Б) Вы используете неизменяемые экземпляры, кэшируете их и возвращаете кэшированный экземпляр из get. Это полезно только в том случае, если ваш индекс списка значим, и вы ожидаете многократного использования одних и тех же значений в своем списке. Если вы сделаете это, то можете также хранить в своей коллекции ссылку на ваш кэшированный экземпляр вместо какого-либо состояния, потому что тогда вы все равно платите только 4 байта за экземпляр за ссылку. В этом случае ваше состояние должно составлять 2 байта или менее, прежде чем имеет смысл сохранять состояние вместо ссылки.

Итак, в качестве окончательного ответа, причина того, что для Flyweight нет универсальной библиотеки, заключается в том, что она платит только при определенных условиях, в противном случае это не стоит того.

Другие вопросы по тегам