【问题标题】:Good pattern for creating an object that supports interning?创建支持实习的对象的好模式?
【发布时间】:2011-08-12 04:42:34
【问题描述】:

我需要一个支持实习的类,比如 Java 的 String 类。在创建类的实例时,如果具有相同参数的引用已经存在,则它应该返回一个预先存在的引用。否则它应该返回一个新的引用。这样:

Foo a = new Foo(5);
Foo b = new Foo(5);
Foo c = new Foo(6);
a == b
a != c

1) 工厂的工作是维护预先存在的对象表,还是表通常只是类本身的一个静态变量?

2) 预先存在的对象表是什么?它是每次请求实例时搜索的一组对象,还是键是对象而值是参数的 Map?

【问题讨论】:

  • 你查看过String的来源吗?
  • String 似乎将本机代码用于其实习方法。
  • 我很好奇:为什么你会需要一个支持实习的对象?
  • @BrunoReis 我在数据库中有一个预先存在的对象图。我的程序中有一个几乎相同的对象图,其中对象由数据库对象组成。用我自己的程序对象图重建数据库对象图,某种对象实习似乎是最简单的方法。我可能错了。
  • 我们在谈论多少个“参数”?如果只有一个(或两个),加上Map(或Map<K,Map<L,E>>)的静态工厂方法应该可以解决问题(或者为了线程安全,使用ConcurrentMap)。您是否需要考虑类加载/卸载,例如应用程序何时可以由容器动态加载/卸载?如果是这样,那么 WeakHashMapWeakReferences。如果有多个参数,那么 PangeaFlyweight + ComputingMap 的建议(很多)更有意义。

标签: java oop design-patterns


【解决方案1】:

我想到了两件事

  1. Flyweight Pattern

  2. Guava's ComputingMap

【讨论】:

  • 是的,“flyweight”模式描述听起来很像字符串实习的java概念,这就是问题所在。从技术上讲,这回答了这个问题(因为它是关于“模式”而不是“实现”)。但是,“番石榴的 ComputingMap”的链接已经过时且损坏了;该类不再存在于番石榴中,也没有解释它做了什么或如何使用它。下面@eric-pilz 的回答提供了有关番石榴Interner 实现的更多详细信息。
【解决方案2】:

如果您可以添加第三方依赖项,请考虑使用 Google Guava 及其 Interners 类。它有两个简单的内部人员:WeakInternerStrongInternerStrongInternerConcurrentMap 为后盾,最适合用于一组小的封闭值。如果您无法控制或以任何方式限制实习对象,那么您可以选择 WeakInterner,它依赖于 WeakReferences。使用WeakInterner 的权衡是性能。

【讨论】:

  • 不错!这很好用。太糟糕了,也没有非线程安全的版本(我只在 1 个线程中使用它)。我想必须将并发级别设置为 1。
【解决方案3】:

您不能使用new 运算符执行此操作,它不会重用现有对象。工厂是做到这一点的最佳方式。 (它可以像类的静态 newInstance 方法一样简单。)通常的数据结构是某种 Map(通常是 HashMap)。一套会贵很多。根据对象的数量,您可以只使用一个数组。 (我认为这可能是 Byte 所做的。)

请注意,不是 String 对象是自动实习的,当您调用 intern 时,它可能会返回不同的 String 实例。例如,此代码将打印“false”:

String a = new String("hello");
String b = new String("hello");
a.intern();
b.intern();
System.out.println(a == b ? "true" : "false");

【讨论】:

  • 所以我的 Foo 类将包含 static Map<Foo,Integer> mFoo newInstance(Integer i) 并且我会检查 m.containsValue(i)?我必须在两个地方(对象和地图)维护我的参数似乎很奇怪。
  • 但是第 3 行和第 4 行没有做任何事情。将它们更改为a = a.intern()b = b.intern(),它将返回“true”。
  • @cgull Line 3 确实做了一些事情,只是不是a。这个例子的重点(也许我没有说清楚)是new 将始终返回一个不同的对象,无论可能设置任何类型的实习。
  • @Jim - 避免创建对象的第二个副本的唯一方法是跟踪您创建的对象。还要注意,该对象可能超出范围。如果您希望被实习对象此时可用于垃圾回收,您可以在实习映射中存储对该对象的 WeakReference。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-13
相关资源
最近更新 更多