我刚学会了原型设计模式。
我是一个Java人,所以很明显我学习了Java实现。但我对来自不同来源的Example实现有一些困惑。
Prototype Using new
Prototype Using new
以上在克隆方法实现中使用new关键字的示例。
以下示例很好,因为它完全是原型定义中所述的实现。
现在,我的问题是,
感谢所有人的回答和评论。虽然他们中的一些人仍然不明白这里的问题。
上述所有作品都是实际问题的序言,我想要解决的问题是 我有一个Cache对象,按其输入的顺序包含30K条目。现在在UI中,我必须根据用户选择以升序或降序显示此数据。我只能处理Cache对象本身,所以想为什么不使用原型模式克隆给定的缓存对象,然后通过用户选择重新排列克隆缓存对象的内容并显示给它们?
我做出了正确的决定吗? 我不是新运营商的敌人,但在这种特殊情况下这不是很贵。吗
我的手中既没有将数据加载到缓存中,也没有任何UI端数据操作。
我能做的只是操纵预先填充的缓存数据。
谢谢Mihir
答案 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对此有一个解决方案。
作为对您的示例的评论
doClone
,它使客户端不知道实例化的实例化类。因此,它没有上述复制构造器的缺点。您可以说它是“封装”或隐藏new
关键字。super.clone()
。但是它也会克服可克隆接口的问题。我个人认为,第一个似乎是首选解决方案,但我从未彻底使用原型模式或可复制接口。