12

所以,我一直在阅读设计模式和原型模式让我感到困惑。我相信使用它的要点之一是避免使用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";
    }
  } 

任何澄清表示赞赏。

4

5 回答 5

10

原型模式的想法是拥有一个蓝图/模板,您可以从中生成您的实例。这不仅仅是“避免在 Java 中使用 new”

如果您在 Java 中实现原型模式,那么可以通过clone()Object 类覆盖现有方法,无需创建新方法。(还需要实现 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");
于 2013-06-20T00:39:44.373 回答
4

设计模式只是一种表示软件如何以可重现的方式编写的方式。实际上有不同的句法方法来实现相同的目标。

因此,原型模式只是一种使用主副本来实现某些覆盖功能的方法。在 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阅读更多内容或查看主要的设计模式站点。那里提供了完整的信息,并附有参考资料。

于 2013-06-20T00:30:38.057 回答
3

您链接的示例是正确的,您的代码

return Tom.clone();

不会编译,因为clone()它不是静态方法。

克隆不是要避免使用new运算符,而是创建一个新实例,该实例具有与被克隆对象相同的状态(其成员字段的值)。因此,clone()它不是静态的,而是一个实例方法,因此您可以创建一个反映已调用对象状态的新实例(并且使用new不是问题)。clone()

只是您的示例类(如 Tom)非常简单(没有状态),该clone()方法所做的只是实例化一个实例。如果它具有更复杂的状态(例如ArrayList对象),则该clone()方法也必须进行深度复制ArrayList

要详细说明您的示例类之一,假设Tom有一些实例 state。现在,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;
    }
}
于 2013-06-20T00:40:05.510 回答
0

你也可以使用 Spring 框架 org.springframework.beans.BeanUtils 提供的 BeanUtils.copyProperties 方法来做同样的事情;

于 2017-09-15T06:32:46.467 回答
0

原型实际上“不”保存对操作员的调用new。它只是通过调用所谓的clone. 例如,

1)你有UserAccount哪个有一个主要用户和链接的用户详细信息

2)UserAccount还有它的PK叫userAccountId

当您将所有UserAccount对象放在一个集合中时,您当然希望userAccountId它们有所不同。但是您仍然必须调用new UserAccount您拥有的每个链接。否则,您最终将修改一个对象 100 次,期望得到 100 件东西作为回报。此外,如果您UserAccount根据属性的敏感性将其作为组合(而不是聚合),您可能也必须调用new它们。

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

于 2019-12-11T12:59:24.327 回答