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

例如,如果 UserAccountPerson 对象(并且如果 'Person' 有它自己的组合),您必须调用 new 以确保它们的引用设置正确。

【讨论】:

以上是关于Java 中的原型模式 - clone() 方法的主要内容,如果未能解决你的问题,请参考以下文章

java原型设计模式

java设计模式-原型(prototype)

java设计模式--原型模式

原型设计模式

原型模式

原型模式--- prototype