0

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

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

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

使用新的
原型 使用新的原型

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

以下示例很好,因为它完全实现了原型定义中的说明。

没有新的原型

现在,我的问题是,

  • 为什么上面的两个例子使用 new 关键字?
  • 如果我们使用 new 关键字,那么这种模式的好处不会消失吗?
  • 如果我对以上 2 个示例有误,请在您的回答中提及原因。
  • 最后,哪个是正确的实现?为什么 ?

更新 28-06-2013

感谢大家的回答和评论。虽然他们中的一些人仍然不明白这里问了什么。

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

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

笔记

既不是将数据加载到缓存中,也不是在我手中,也不是任何 UI 端数据操作。

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

谢谢米希尔

4

2 回答 2

2

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

因此,您可以使用clone() (仅在内部使用 new)或自己创建一个实例(使用复制构造函数或在构造后显式触发 setter)来镜像源对象的状态。

在你的第三个例子中

clonedAnimal = (Animal) super.clone();

实际上是在调用Object.clone()它在这里创建实例。

另外,尝试删除后面的clonedAnimal.setXXX()方法,它应该仍然可以工作,因为默认情况下应该已经创建了一个浅拷贝Object.clone()。他们可能把它们留在那里是为了便于理解。

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

为什么?因此,它也复制了状态。但是,这并不能保证new没有被使用。只是对象的类暴露了一个clone()实现来承担创建副本的负担。

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

但是,这不是重点。重要的是了解何时return super.clone()会真正返回一个独立的克隆对象。即使对于中等复杂的对象,答案也大多是“否”,因为它执行的是浅拷贝

因此,如果您的缓存对象占用大量资源,您将不得不提供自己的实现来克隆缓存对象。举个例子:假设您的缓存有一个LinkedHashMap最近访问的对象。super.clone()如果你独自依靠;您克隆的缓存对象(通过浅拷贝)将只有一个对您的Map的引用的副本,这意味着如果您清除其中一个缓存,另一个也将被清除。

因此,当我说通过委托使用newclone()时;我指的是为克隆提供自己的深拷贝实现(几乎总是如此)的类。而且,由于他们是在 Java 的范围内进行的,所以他们的第一步(除了反射 API)是使用new运算符实例化一个新对象。

于 2013-06-26T08:38:21.430 回答
1

在 Java 中,您可以通过两种方式创建对象:使用new或使用可克隆接口和调用super.clone(). 您可能想看看这个问题,它讨论了 Java 的可克隆接口。Cloneable 本质上是 Java 自己的原型模式实现。正如它所说,可克隆接口有几个缺陷。为避免这些,您必须new在代码中的某处使用。

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

作为对您的示例的评论

  1. 这使用了复制构造方法。它还提供了一个很好的包装方法doClone,它使客户端不知道实际实例化的类。因此它没有上面提到的复制构造函数的缺点。您可以说它是一种“封装”或隐藏new关键字。
  2. 这个例子被打破了。不要这样做!它只创建一个新对象,但不复制其状态。这违反了原型模式以及可克隆接口!
  3. 这是可克隆接口的正确实现。super.clone()每当实现可克隆接口时都应使用调用。然而,它也确实存在可克隆接口的问题。

我个人的看法是,第一个似乎是更可取的解决方案,尽管我从未彻底使用过原型模式或可克隆接口。

于 2013-06-26T08:54:29.677 回答