如有转载,请申明:
转载至 http://blog.csdn.net/qq_35064774/article/details/52102397
1 什么是原始模型模式
原始模型模式属于对象的构建模式。通过给出一个原型对象来指明所要创建的对象的类型,然后复制这个原型对象的办法创建出更多同类型的对象。
通俗来说,就是通过存在的对象创建出n份相同的对象,也就是对象拷贝。而java对这模式有很好的支持,有克隆接口。
2 如何实现原始模型模式
对于对象拷贝来说,存在两种,一种是浅拷贝,一种是深拷贝。
两者唯一的区别其实也很简单。
深拷贝会把对象内部引用的对象也拷贝一份,而浅拷贝不会。
接下来我们写一个例子来测试这两种拷贝。
首先我们先设计一个接口,它继承Cloneable 接口,重写Object类的clone()方法。
package com.ittianyu.prototype;
public interface Prototype extends Cloneable {
public Object clone() throws CloneNotSupportedException;
}
你可能问既然java支持clone,为什么还要这么麻烦特地定义一个接口。这里为了强制实现它的类必须重写clone方法。同时这种方式也可以在c++中使用。
然后我们定义两个实现了这个接口的类,分别是Car和Person。Car实现的是浅拷贝,直接调用父类Object的clone方法作为实现。Person对象中含有Car对象,所以实现的是深拷贝,这里的深拷贝实现,我采用的是串行化的方式,这方式通用性强,缺点也很明显,就是必须实现Serializable。
package com.ittianyu.prototype;
import java.io.Serializable;
public class Car implements Prototype, Serializable{
private String name;
public Car(String name) {
super();
this.name = name;
}
/**
* 直接调用Object的clone实现浅拷贝
*/
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Car [name=" + name + "]";
}
}
package com.ittianyu.prototype;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Person implements Prototype, Serializable {
private String name;
private Car car;
public Person(String name, Car car) {
super();
this.name = name;
this.car = car;
}
public Car getCar() {
return car;
}
@Override
public String toString() {
return "Person [name=" + name + ", car=" + car + "]";
}
/**
* 通过序列化实现深拷贝
*/
@Override
public Object clone() throws CloneNotSupportedException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos;
try {
// write
oos = new ObjectOutputStream(baos);
oos.writeObject(this);
// read
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
throw new CloneNotSupportedException();
}
}
}
对于深拷贝,其实也很简单,就是把整个对象通过ObjectOutputStream 写到内存,然后通过ObjectInputStream读取出来。
把对象写入内存时,就是将整个对象深拷贝了一份,串行化的方式放到内存。
最后是测试类。
package com.ittianyu.prototype;
public class Test {
public static void main(String[] args) {
// 浅拷贝测试
Car car = new Car("奔驰");
System.out.println(car);
try {
System.out.println(car.clone());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
// 深拷贝测试
Person person = new Person("Mike", car);
System.out.println(person);
try {
Person clonePerson = (Person) person.clone();
System.out.println(clonePerson);
System.out.println("clonePerson.getCar() == person.getCar() is "
+ (clonePerson.getCar() == person.getCar()));
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
3 在什么情况下使用原始模型模式
引用《Java与模式》中的说明。
假设一个系统的产品类是动态加载的,而且产品类具有一定的等级结构。这个时候如果采取工厂模式的话,工厂类就不得不具有一个相应的等级结构。而产品类的等级结构一旦变化,工厂类的等级结构就不得不有一个相应的变化。这对于产品结构可能会有经常性变化的系统来说,采用工厂模式就有不方便之处。
这时如果采取原始模型模式,给每一个产品类配备一个克隆方法(大多数的时候只需给产品类等级结构的根类配备一个克隆方法),便可以避免使用工厂模式所带来的具有固定等级结构的工厂类。
4 原始模型模式的优点和缺点
优点:
* 原始模型模式允许动态地增加或减少产品类。由于创建产品类实例的方法是产品类内部具有的,因此,增加新产品对整个结构没有影响。
* 原始模型模式提供简化的创建结构。
* 具有给一个应用软件动态加载新功能的能力。
* 产品类不需要非得有任何事先确定的等级结构,因为原始模型模式适用于任何的等级结构。
缺点:
* 要支持该模式的每个类都必须配备一个克隆方法。