原型设计模式Java实现混乱

时间:2013-06-26 08:17:37

标签: java oop design-patterns prototype-pattern

我刚学会了原型设计模式。

我是一个Java人,所以很明显我学习了Java实现。但我对来自不同来源的Example实现有一些困惑。

我认为这些例子可能是错误的

Prototype Using new
Prototype Using new

以上在克隆方法实现中使用new关键字的示例。

以下示例很好,因为它完全是原型定义中所述的实现。

Prototype Without new

现在,我的问题是,

  • 上述两个示例为何使用新关键字?
  • 如果我们使用新关键字,那么这种模式的好处是否会消失?
  • 如果我对上述两个例子有误,请在答案中提及原因。
  • 最后,这是正确的实施?为什么?

更新28-06-2013

感谢所有人的回答和评论。虽然他们中的一些人仍然不明白这里的问题。

上述所有作品都是实际问题的序言,我想要解决的问题是 我有一个Cache对象,按其输入的顺序包含30K条目。现在在UI中,我必须根据用户选择以升序或降序显示此数据。我只能处理Cache对象本身,所以想为什么不使用原型模式克隆给定的缓存对象,然后通过用户选择重新排列克隆缓存对象的内容并显示给它们?

我做出了正确的决定吗? 我不是新运营商的敌人,但在这种特殊情况下这不是很贵。吗

注意

我的手中既没有将数据加载到缓存中,也没有任何UI端数据操作。

我能做的只是操纵预先填充的缓存数据。

谢谢Mihir

2 个答案:

答案 0 :(得分:2)

克隆不是避免使用new运算符,而是创建一个与正在克隆的对象具有相同状态(其成员字段的值)的新实例。

因此,您可以使用clone() (内部仅使用新的)或自己创建实例(使用副本构造函数或明确地在构造后触发setter)以镜像源对象的状态。

在你的第三个例子中

clonedAnimal = (Animal) super.clone();

实际上是在调用Object.clone()来创建 new 实例。

此外,请尝试删除后面的clonedAnimal.setXXX()方法,它应该仍然有效,因为默认情况下,{em>浅层副本应该已由Object.clone()创建。为了便于理解,他们可能将他们留在那里。

编辑 :(回应OP的评论)
当您clone()时,您基本上将new obj()调用委托给原始对象本身。

为什么呢?所以,它也复制了州。但是,这并不能保证 new 没有被使用;只是对象的类暴露了clone()实现,以承担在自身上创建副本的负担。

这是事情变得有趣的地方。 Object.clone()原生方法。它是在JVM中实现的,它用 C ++ 来分配内存和所有其他爵士乐。但是,当您自己调用 new 运算符时,JVM的作用几乎相同(除了复制对象状态之外)。

但是,这不是重点。重要的是要了解return super.clone()何时真正返回独立克隆对象。即使对于中度复杂的对象,答案仍然是 ,大部分都是 ,因为它会执行浅层复制

因此,如果您的缓存对象资源很多,则必须为缓存对象的克隆提供自己的实现。举个例子:让我们假设你的缓存有一个LinkedHashMap最近访问过的对象。如果你单独依靠super.clone();克隆的缓存对象(通过浅拷贝)只有副本 Map ,这意味着如果你清除了一个缓存,另一个也会被清除。

因此,当我说 new 通过授权使用clone()时;我指的是为克隆提供自己的深层拷贝实现(几乎总是如此)的类。而且,由于他们是在Java的范围内完成的,因此他们的第一步(禁止Reflection API)是使用 new 运算符实例化一个新对象。

答案 1 :(得分:1)

在Java中,您可以通过两种方式创建对象:使用new或使用可克隆接口并调用super.clone()。您可能需要查看this question,其中讨论了Java的可克隆接口。 Cloneable本质上是Java自己的原型模式实现。因为它声明可克隆接口有几个缺陷。要避免这些,您必须在代码中的某处使用new

克隆的替代方法是提供复制构造函数,即public MyClass(MyClass other) {...。这样做的一个缺点是,您必须声明原型模式试图阻止的创建类型的确切类。然而,例1对此有一个解决方案。

作为对您的示例的评论

  1. 这使用了复制构造方法。它还提供了一个很好的包装器方法doClone,它使客户端不知道实例化的实例化类。因此,它没有上述复制构造器的缺点。您可以说它是“封装”或隐藏new关键字。
  2. 此示例已中断。 不要这样做!它只会创建一个新对象,但不会复制其状态。这违反了原型模式以及可克隆的界面!
  3. 这是可克隆接口的正确实现。每当实现可克隆接口时,都应该使用调用super.clone()。但是它也会克服可克隆接口的问题。
  4. 我个人认为,第一个似乎是首选解决方案,但我从未彻底使用原型模式或可复制接口。