那里有Java flyweight模式实现吗?

时间:2011-07-27 07:44:24

标签: java design-patterns flyweight-pattern

我一直在寻找一个flyweight模式实现,并在达到Google搜索的第20页后放弃了。虽然有无数愚蠢的例子,但似乎没有人发表过Java中可重用的实现。

对我来说,如果你必须保留很多这样的实例,flyweight才有意义,所以必须将它作为集合实现。我想要的是一个Factory,它接受一个byte / short / int / long mapper 实现,并返回一个List,Set或Map,它看起来像一个普通的Object集合,但是在内部存储它的数据作为一个原始数组,从而节省了大量的ram。映射器将采用X类型的对象,并将其映射到基元,或者反过来执行。

在某处可以找到类似的东西吗?

[编辑]我正在寻找一个支持这种模式的 Collection 库,而不仅仅是任何一个例子,其中有数百个。

6 个答案:

答案 0 :(得分:3)

如果要替换List,可以改用TByteArrayList。如果你用ant替换List中的MyClass {int a; T对象;你可以改用TIntObjectHashMap。

如果要用两个必须排序的字段或三个或更多字段替换某些内容,则需要实现自己的类,该类包装数组以保存数据。这是使用基于列的表模型。

e.g。

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行

编辑: Integer的Autoboxing使用IntegerCache,它是一个集合。 ArrayList是一个包装数组且具有大小...的类

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

答案 1 :(得分:2)

我认为,Integer.valueOf(String s)非常轻量级。因为据我所知,它在内部保留了一些已创建的Integers,因此,当您传递之前传递的String时,它会返回一个现有实例。

答案 2 :(得分:1)

你见过四人帮 - 设计模式吗?如果你愿意,我会重写他们的实现(尽管它是在C ++中),但是稍后。

这是你应该拥有的那本书之一 - 永远不知道它什么时候会派上用场。

答案 3 :(得分:1)

根据您的要求,我认为您应该尝试TroveColt。这些图书馆支持原始馆藏。

答案 4 :(得分:1)

GNU Trove使用gnu.trove.decorator包执行此类操作(仅限地图和设置,而不是列表)。

但是这种事情效率很低,我怀疑在很多情况下权衡是值得的。

为什么不使用适当的原始集合?

答案 5 :(得分:0)

我做了一个测试程序,看看Flyweight在Java中的效果如何。为了记录,我将在这里描述我的结果。 YMMV

1)如果对象中有多个字段,则可以通过将它们拼接在一个int或long中来节省一些CPU。这对程序很容易出错并且容易出错,但速度提高了几个百分点,因为多个数组访问比位操作更昂贵。随着字段数量的增加,情况会更多。

2)对于小实例(4个字节的状态)它将比直接存储实例慢大约25%。但是,仅在每次获取时都不创建新实例。这就是真正的问题所在。必须在每次获取时创建一个新实例非常昂贵;在这种情况下,它不会慢25%,但会慢500%!

3)我在get上看到了两种保存实例创建的方法:

A)您的get方法填写预先存在的实例,而不是创建新实例。换句话说,您将结果对象作为输入传递给get方法。

B)您使用不可变实例,缓存它们,并从get返回缓存实例。这仅在列表索引很重要时才有用,并且您希望在列表中多次重复使用相同的值。如果你这样做,那么你也可以直接存储对集合中缓存实例的引用,而不是某些状态,因为那样你只需为每个实例支付4个字节作为引用。在这种情况下,在存储状态而不是引用之前,您的状态必须是2个字节或更少。

因此,作为最终答案,Flyweight没有通用库的原因是它只在特定条件下付费,否则它不值得。