Java 中的原型模式 - clone() 方法
Posted
技术标签:
【中文标题】Java 中的原型模式 - clone() 方法【英文标题】:Prototype Pattern in Java - the clone() method 【发布时间】:2013-06-16 17:03:42 【问题描述】:所以,我一直在阅读设计模式,而原型模式让我感到困惑。我相信使用它的要点之一是避免使用 new 运算符。那我看这个例子:
http://sourcemaking.com/design_patterns/prototype/java/1
首先,他们的 Prototype 想法实现了一个 clone() 方法,这很奇怪。***还说我需要一个纯虚拟方法克隆来由子类实现(为什么?)。 Java 不是已经提供了这样的方法,完全按照我们的需要(即创建对象的副本而不是从头开始实例化它)吗?其次,clone方法调用操作符new!这个例子肯定是错的吗? (在那种情况下,我应该在其他地方学习设计模式,嗯?)。有人可以判断这个更正是否正确吗?:
static class Tom implements Cloneable implements Xyz
public Xyz cloan()
return Tom.clone(); //instead of new I use clone() from Interface Cloneable
public String toString()
return "ttt";
感谢任何澄清。
【问题讨论】:
"I use clone() from Interface Cloneable" 接口Cloneable
中没有clone()
【参考方案1】:
设计模式只是一种表示软件如何以可重现方式编写的方式。实际上有不同的句法方法来实现相同的目标。
因此,原型模式只是一种使用主副本来实现某些覆盖功能的方法。在 Java 中有几种方法可以做到这一点(我也相信其他语言)。这是一个使用“new”关键字的方法,它基于使用接口作为实现具体类的契约。然后单个方法采用接口的具体实现并执行相同的操作:
// software contract
interface Shape
public void draw();
// concrete implementations
class Line implements Shape
public void draw()
System.out.println("line");
class Square implements Shape
public void draw()
System.out.println("square");
...
class Painting
public static void main (String[] args)
Shape s1 = new Line ();
Shape s2 = new Square ();
...
paint (s1);
paint (s2);
...
// single method executes against the software contract as a prototype
static void paint (Shape s)
s.draw ();
您可以在http://www.javacamp.org/designPattern/prototype.html 阅读更多信息或查看main Design Pattern site。那里提供了完整的信息,并附有参考资料。
【讨论】:
乍一看,这个实现更像我所期待的。感谢您指出。我知道实现模式的细节可能会有所不同,但我仍然觉得我链接的那个有问题(可能还有***?)。【参考方案2】:原型模式的想法是拥有一个蓝图/模板,您可以从中生成实例。这不仅仅是“避免在 Java 中使用 new”
如果你在 Java 中实现原型模式,那么可以通过 Object 类重写现有的 clone()
方法,无需创建新方法。 (还需要实现 Clonable 接口,否则会出现异常)
举个例子:
// Student class implements Clonable
Student rookieStudentPrototype = new Student();
rookieStudentPrototype.setStatus("Rookie");
rookieStudentPrototype.setYear(1);
// By using prototype pattern here we don't need to re-set status and
// year, only the name. Status and year already copied by clone
Student tom = rookieStudentPrototype.clone();
tom.setName("Tom");
Student sarah = rookieStudentPrototype.clone();
sarah.setName("Sarah");
【讨论】:
"利用 Cloneable 接口中现有的 clone() 方法"Cloneable
接口中没有 clone()
方法
如果您到处使用克隆方法到处乱跑,您可能会遇到一些讨厌的问题。在现实生活中,您必须决定是要进行深层克隆还是浅层克隆。克隆 List 实现或二维数组呢?上面是一个非常简单的例子。通常,更好的方法是有效处理这些情况的复制构造函数。 In Effective Java, Josh Bloch says the Cloneable interface is severely broken.【参考方案3】:
你链接的例子是正确的,你的代码
return Tom.clone();
不会编译,因为clone()
不是静态方法。
克隆并不是要避免使用new
运算符,而是创建一个与被克隆对象具有相同状态(其成员字段的值)的新实例。因此,clone()
不是静态的,而是一个实例方法,因此您可以创建一个反映 clone()
的对象状态的新实例(并且使用 new 不是问题)调用。
只是您的示例类(如 Tom)非常简单(没有状态),clone()
方法所做的只是实例化一个 new 实例。如果它有更复杂的状态(比如对象的ArrayList
),clone()
方法也必须对ArrayList
进行深层复制。
要详细说明您的示例类之一,假设Tom
有一些实例状态。现在,clone()
还必须确保返回的副本与当前副本的状态相匹配。
static class Tom implements Xyz
private String name;
public Tom()
this.name = "Tom"; // some state
public Xyz clone()
Tom t = new Tom();
t.setName(getName()); // copy current state
return t;
public String toString()
return getName();
public String getName()
return name;
public void setName(String name)
this.name = name;
【讨论】:
你的意思是,如果该类有一个 ArrayList(或任何其他属性),我的克隆(或 cloan(),在我的例子中)方法将创建一个“new Tom()”,然后继续将存储在原型中的属性值复制到新对象上?如果是这样,我明白了,问题是这个例子并没有很好地突出原型的有用性。谢谢! 是的,我就是这个意思。我还添加了一个示例来强调这一点。【参考方案4】:你也可以使用 Spring 框架 org.springframework.beans.BeanUtils 提供的 BeanUtils.copyProperties 方法来做同样的事情;
【讨论】:
【参考方案5】:原型实际上 “不” 保存对 new
运算符的调用。它只是通过调用所谓的clone
来简化非敏感属性的浅拷贝。例如,
1) 你有UserAccount
,它有一个主要用户和链接的用户详细信息
2) UserAccount
也有它的 PK 叫 userAccountId
。
当您将所有UserAccount
对象放在一个集合中时,您当然希望userAccountId
有所不同。但是您仍然需要为您拥有的每个链接致电new UserAccount
。否则,您最终将修改一个对象 100 次,期望得到 100 件东西作为回报。此外,如果您根据属性的敏感性将此 UserAccount
作为组合(而不是聚合),您可能还需要对它们调用 new
。
例如,如果 UserAccount
有 Person
对象(并且如果 'Person' 有它自己的组合),您必须调用 new
以确保它们的引用设置正确。
【讨论】:
以上是关于Java 中的原型模式 - clone() 方法的主要内容,如果未能解决你的问题,请参考以下文章