Skip to main content

原型模式

当创建对象复杂的时候,可以使用原型方式快捷创建对象,通过使用原型来克隆。

原型模式包括:

  • 抽象原型类:规定了具体原型类必须实现的 clone() 抽象方法
  • 具体原型类:继承抽象原型类,实现 clone() 方法,是可被复制的对象
  • 访问类:使用具体原型类的 clone() 方法复制新对象

克隆分为深克隆和浅克隆。浅克隆创建新对象,成员和原来的对象完全相同,对于非基本类型的成员,指向原有对象内存地址。深克隆的引用对象也会被克隆,不会指向原有对象的地址。

Java 种 Object 类提供了 clone() 方法实现浅克隆。

抽象原型类

public abstract class Prototype implements Cloneable {

public Prototype clone() throws CloneNotSupportedException {
return (Prototype) super.clone();
}

}

具体原型类

public class ConcretePrototype1 extends Prototype {
@Override
public ConcretePrototype1 clone() throws CloneNotSupportedException {
return (ConcretePrototype1)super.clone();
}
}

具体原型类也可以直接实现 Cloneable 接口

public class ConcretePrototype2 implements Cloneable {

@Override
public ConcretePrototype2 clone() throws CloneNotSupportedException {
return (ConcretePrototype2) super.clone();
}
}

测试类

public class TestPrototype {
public static void main(String[] args) throws CloneNotSupportedException {

ConcretePrototype1 c1 = new ConcretePrototype1();
ConcretePrototype1 c2 = c1.clone();
System.out.println(c1==c2); //false
}
}

扩展:实现深克隆

public class ConcretePrototype1 extends Prototype {

Date date;

public Date getDate() {
return date;
}

public void setDate(Date date) {
this.date = date;
}

@Override
public ConcretePrototype1 clone() throws CloneNotSupportedException {
return (ConcretePrototype1)super.clone();
}

@Override
public String toString() {
return "ConcretePrototype1{" +
"date=" + date +
'}';
}
}

测试类。改变克隆对象的成员,原型的成员也改变,因为引用的是同一个对象。

public class TestPrototype {
public static void main(String[] args) throws CloneNotSupportedException {

ConcretePrototype1 c1 = new ConcretePrototype1();
c1.setDate(new Date());
ConcretePrototype1 c2 = c1.clone();
c2.getDate().setTime(111);
System.out.println("c1==c2? "+ (c1==c2));
System.out.println("c1: "+c1);
System.out.println("c2: "+c2);
}
}
/*
输出:
c1: ConcretePrototype1{date=Sat Feb 12 22:20:49 CST 2022}
c1==c2? false
c1: ConcretePrototype1{date=Thu Jan 01 08:00:00 CST 1970}
c2: ConcretePrototype1{date=Thu Jan 01 08:00:00 CST 1970}
*/

ConcretePrototype1 实现序列号接口

public class ConcretePrototype1 extends Prototype implements Serializable {
//...
}

深克隆。这样 Date 成员就是一个新的对象

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));
oos.writeObject(c1);
oos.close();

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));
ConcretePrototype1 c3 = (ConcretePrototype1) ois.readObject();