简介
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。
类图
●Prototype(抽象原型类):它是声明克隆方法的接口,是所有具体原型类的公共父类,可以是抽象类也可以是接口,甚至还可以是具体实现类。
● ConcretePrototype(具体原型类):它实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。
● Client(客户类):让一个原型对象克隆自身从而创建一个新的对象,在客户类中只需要直接实例化或通过工厂方法等方式创建一个原型对象,再通过调用该对象的克隆方法即可得到多个相同的对象。代码
/**
* 具体原型类:它实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。
* @author: 张彬
* @date: 2018年5月15日 上午10:48:00
* @version: V1.0
* @review: 张彬/2018年5月15日 上午10:48:00
*/
public class ConcretePrototype implements Cloneable {
private String name;
private String adress;
private List<String> phones;
@Override
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAdress() {
return adress;
}
public void setAdress(String adress) {
this.adress = adress;
}
public List<String> getPhones() {
return phones;
}
public void setPhones(List<String> phones) {
this.phones = phones;
}
public void show(){
System.out.println("name:"+this.getName());
System.out.println("adress:"+this.getAdress());
System.out.println("phones:"+this.getPhones());
System.out.println("------------------");
}
}
/**
* 客户端
* @author: 张彬
* @date: 2018年5月15日 上午10:51:34
* @version: V1.0
* @review: 张彬/2018年5月15日 上午10:51:34
*/
public class Client {
public static void main(String[] args) throws OptionalDataException, ClassNotFoundException, IOException {
ConcretePrototype cp = new ConcretePrototype();
List<String> phones = new ArrayList<String>();
phones.add("15111371512");
phones.add("0315-7566828");
cp.setName("zz");
cp.setAdress("石景山");
cp.setPhones(phones);
ConcretePrototype copy = (ConcretePrototype) cp.clone();
copy.show();
cp.setName("zb");
cp.setAdress("石景山实兴大街");
phones.add("199325671568");
copy.show();
}
}
输出结果:
name:zz
adress:石景山
phones:[15111371512, 0315-7566828]
------------------
name:zz
adress:石景山
phones:[15111371512, 0315-7566828, 199325671568]
------------------
通过输出结果发现,在克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制,这就是浅克隆的缺陷。我们可以通过序列化实现深度克隆解决这个问题
深克隆
/**
* 具体原型类
* @author: 张彬
* @date: 2018年5月15日 上午10:48:00
* @version: V1.0
* @review: 张彬/2018年5月15日 上午10:48:00
*/
public class ConcretePrototype2 implements Serializable {
private String name;
private String adress;
private List<String> phones;
//使用序列化技术实现深克隆
public Object deepClone() throws IOException, ClassNotFoundException, OptionalDataException{
//将对象写入流中
ByteArrayOutputStream bao=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bao);
oos.writeObject(this);
//将对象从流中取出
ByteArrayInputStream bis=new ByteArrayInputStream(bao.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bis);
return ois.readObject();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAdress() {
return adress;
}
public void setAdress(String adress) {
this.adress = adress;
}
public List<String> getPhones() {
return phones;
}
public void setPhones(List<String> phones) {
this.phones = phones;
}
public void show(){
System.out.println("name:"+this.getName());
System.out.println("adress:"+this.getAdress());
System.out.println("phones:"+this.getPhones());
System.out.println("------------------");
}
}
/**
* 客户端
* @author: 张彬
* @date: 2018年5月15日 上午10:51:34
* @version: V1.0
* @review: 张彬/2018年5月15日 上午10:51:34
*/
public class Client {
public static void main(String[] args) throws OptionalDataException, ClassNotFoundException, IOException {
ConcretePrototype2 cp2 = new ConcretePrototype2();
List<String> phones2 = new ArrayList<String>();
phones2.add("15111371512");
phones2.add("0315-7566828");
cp2.setName("zz");
cp2.setAdress("石景山");
cp2.setPhones(phones2);
ConcretePrototype2 deepCopy = (ConcretePrototype2) cp2.deepClone();
deepCopy.show();
cp2.setName("zb");
cp2.setAdress("石景山实兴大街");
phones2.add("199325671568");
deepCopy.show();
cp2.show();
}
}
输出结果:
name:zz
adress:石景山
phones:[15111371512, 0315-7566828]
------------------
name:zz
adress:石景山
phones:[15111371512, 0315-7566828]
------------------
name:zb
adress:石景山实兴大街
phones:[15111371512, 0315-7566828, 199325671568]
------------------
总结
优点:
1、性能提高。
2、逃避构造函数的约束。
缺点:
1、 需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当对已有的类进行改造时,需要修改源代码,违背了“开闭原则”。
2、在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重的嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来可能会比较麻烦。