我一直在寻找一个flyweight模式实现,并在达到Google搜索的第20页后放弃了。虽然有无数愚蠢的例子,但似乎没有人发表过Java中可重用的实现。
对我来说,如果你必须保留很多这样的实例,flyweight才有意义,所以必须将它作为集合实现。我想要的是一个Factory,它接受一个byte / short / int / long mapper 实现,并返回一个List,Set或Map,它看起来像一个普通的Object集合,但是在内部存储它的数据作为一个原始数组,从而节省了大量的ram。映射器将采用X类型的对象,并将其映射到基元,或者反过来执行。
在某处可以找到类似的东西吗?
[编辑]我正在寻找一个支持这种模式的 Collection 库,而不仅仅是任何一个例子,其中有数百个。
答案 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)
答案 4 :(得分:1)
答案 5 :(得分:0)
我做了一个测试程序,看看Flyweight在Java中的效果如何。为了记录,我将在这里描述我的结果。 YMMV
1)如果对象中有多个字段,则可以通过将它们拼接在一个int或long中来节省一些CPU。这对程序很容易出错并且容易出错,但速度提高了几个百分点,因为多个数组访问比位操作更昂贵。随着字段数量的增加,情况会更多。
2)对于小实例(4个字节的状态)它将比直接存储实例慢大约25%。但是,仅在每次获取时都不创建新实例。这就是真正的问题所在。必须在每次获取时创建一个新实例非常昂贵;在这种情况下,它不会慢25%,但会慢500%!
3)我在get上看到了两种保存实例创建的方法:
A)您的get方法填写预先存在的实例,而不是创建新实例。换句话说,您将结果对象作为输入传递给get方法。
B)您使用不可变实例,缓存它们,并从get返回缓存实例。这仅在列表索引很重要时才有用,并且您希望在列表中多次重复使用相同的值。如果你这样做,那么你也可以直接存储对集合中缓存实例的引用,而不是某些状态,因为那样你只需为每个实例支付4个字节作为引用。在这种情况下,在存储状态而不是引用之前,您的状态必须是2个字节或更少。
因此,作为最终答案,Flyweight没有通用库的原因是它只在特定条件下付费,否则它不值得。