原型模式虽然是创建型的模式,但是与工程模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象在 Java 中,复制对象是通过 clone()实现的,先创建一个原型类:
public class Prototype implements Cloneable { public Object clone() throws CloneNotSupportedException { Prototype proto = (Prototype) super .clone(); return proto; } }
一个原型类,只需要实现 Cloneable 接口,覆写 clone 方法,此处 clone 方法可以改成任意的名称,因为 Cloneable 接口是个空接口,你可以任意定义实现类的方法名,如 cloneA 或者 cloneB,因为此处的重点是super.clone()这句话, super.clone()调用的是Object的clone()方法, 而在Object类中,clone()是 native 的,首先需要了解对象深、浅复制的概念:
浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。
深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。
1 package com.swust.原型设计模式; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.ByteArrayOutputStream; 5 import java.io.IOException; 6 import java.io.ObjectInputStream; 7 import java.io.ObjectOutputStream; 8 import java.io.Serializable; 9 10 class BaseClass implements Serializable { 11 12 private String name; 13 14 public String getName() { 15 return name; 16 } 17 public void setName(String name) { 18 this.name = name; 19 } 20 } 21 22 class NewClass implements Serializable { 23 private static final long serialVersionUID = 1L; 24 private String id; 25 private BaseClass baseClass; 26 27 public BaseClass getBaseClass() { 28 return baseClass; 29 } 30 public void setBaseClass(BaseClass baseClass) { 31 this.baseClass = baseClass; 32 } 33 public String getId() { 34 return id; 35 } 36 public void setId(String id) { 37 this.id = id; 38 } 39 40 41 public Object deepClone() throws IOException, ClassNotFoundException{ 42 ByteArrayOutputStream bo = new ByteArrayOutputStream(); 43 ObjectOutputStream oo = new ObjectOutputStream(bo); 44 oo.writeObject(this); 45 46 ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); 47 ObjectInputStream oi = new ObjectInputStream(bi); 48 return oi.readObject(); 49 } 50 51 } 52 53 public class PrototypeSe { 54 public static void main(String[] args) throws ClassNotFoundException, IOException { 55 BaseClass baseClass = new BaseClass(); 56 baseClass.setName(""); 57 NewClass newClass = new NewClass(); 58 newClass.setBaseClass(baseClass); 59 60 NewClass newClass2 = (NewClass)newClass.deepClone(); 61 newClass2.getBaseClass().setName("深复制生成对象所设置的属性……"); 62 63 System.out.println("两个类是否相等:"+(newClass==newClass2)); 64 System.out.println("这两个类是否属于同一类型:"+(newClass.getClass()==newClass2.getClass())); 65 } 66 }
原型模式的优点
原型模式允许在运行时动态改变具体的实现类型。原型模式可以在运行期间,由客户来注册符合原型接口的实现类型,也可以动态地改变具体的实现类型,看起来接口没有任何变化,但其实运行的已经是另外一个类实例了。因为克隆一个原型就类似于实例化一个类。
原型模式的缺点
原型模式最主要的缺点是每一个类都必须配备一个克隆方法。配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类来说不是很难,而对于已经有的类不一定很容易,特别是当一个类引用不支持序列化的间接对象,或者引用含有循环结构的时候。