Prototype Pattern in Java - the clone() method

一世执手 提交于 2019-12-18 04:42:15

问题


So, I've been reading on Design Patterns and the Prototype Patterns confuses me. I believe one of the points of using it is avoiding the need for using the new operator. Then I look at this example:

http://sourcemaking.com/design_patterns/prototype/java/1

First, Their idea of Prototype implements a clone() method, which is weird. Wikipedia also says I need a pure virtual method clone to be implemented by subclasses (why?). Doesn't Java already provide such a method, doing exactly what we need it to do (which is to create a copy of an object instead of instancing it from scratch)? Second, the clone method invokes the operator new! Surely the example is wrong? (In that case I should be studying Design Patterns elsewhere, heh?). Can someone tell if this correction makes it right?:

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";
    }
  } 

Any clarification is appreciated.


回答1:


The idea of prototype pattern is having a blueprint / template from which you can spawn your instance. It's not merely to "avoid using new in Java"

If you implement prototype pattern in Java, then yes by all means override the existing clone() method from Object class, no need to create a new one. (Also need implement Clonable interface or you'll get exception)

As an example:

// 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");



回答2:


A design pattern is simply a way of representing how software is written in a reproducible way. There are in fact different syntactical approaches to achieving the same thing.

So, the Prototype pattern is simply an approach that uses a master copy to implement some overriding functionality. There are several ways to do this in Java (as well, I believe in other languages). Here is one that uses the 'new' keyword, and it's based on using an interface as a contract with implementing concrete classes. Then a single method takes a concrete implementation of the interface and performs the same operation:

// 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 ();
   }
}

You can read more at http://www.javacamp.org/designPattern/prototype.html or check out the main Design Pattern site. The information is presented there complete with references.




回答3:


The example you've linked is correct and your code

return Tom.clone();

won't compile because clone() is not a static method.

Cloning is not about avoiding the use of new operator but creating a new instance that has the same state (values of its member fields) as that of the object that's being cloned. Hence, clone() is not static but an instance method so that you can create a new instance (and using new isn't a problem) that mirrors the state of the object that clone() has been invoked upon.

It's just that your example classes (like Tom) are so simple (with no state) that all that the clone() method is doing is to instantiate a new instance. If it had a bit more complex state (say an ArrayList of objects) the clone() method would have to do a deep copy of the ArrayList as well.

To elaborate with one of your example classes, assume that Tom had some instance state. Now, the clone() would also have to make sure that the copy being returned matches the state of the current one.

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;
    }
}



回答4:


You can also use BeanUtils.copyProperties method to do the same which is provided by Spring framework org.springframework.beans.BeanUtils;




回答5:


Prototype actually "Doesn't" save calls to new operator. It simply facilitates that a shallow copy of non-sensitive attributes are made by calling the so called clone. For example,

1) You have UserAccount which has a primary user and linked user details

2) UserAccount also has it's PK called userAccountId.

When you put all your UserAccount objects in a collection, of course, you would like the userAccountId to be different. But you still have to call new UserAccount for each links you have. Otherwise, you will end up modifying one object 100 times expecting 100 things in return. Also, if you have this UserAccount as a composition (not aggregation) depending on the attribute's sensitivity, you may have to call new on them too.

e.g if UserAccount has Person object (and if 'Person' has it's own compositions), you have to call new to ensure that their references are appropriately set.



来源:https://stackoverflow.com/questions/17203493/prototype-pattern-in-java-the-clone-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!