概念
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
角色
抽象原型类:声明克隆方法的接口,不过java里面实现Cloneable接口就ok的。
具体原型类:实现克隆方法。
let's look the code
这里先不实现Cloneable接口,大概自己写一下。
抽象原型类
public abstract class Human {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 定义克隆方法
*/
public abstract Human clone();
}
具体原型类
public class Man extends Human {
public Human clone(){
Man man = new Man();
man.setName(getName());
return man;
};
}
这样就大概模拟了一下克隆。 一般来说,实现的两个对象之间会满足如下关系:
(1) 对任何对象x,都有x.clone() != x,即克隆对象与原型对象不是同一个对象;
(2) 对任何对象x,都有x.clone().getClass() == x.getClass(),即克隆对象与原型对象的类型一样;
(3) 如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。
下面用Cloneable实现一下。
抽象原型类
这里用基类来代替。
public class Human implements Cloneable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//定义克隆方法,调用Object的clone方法
public Human clone() {
Object obj = null;
try {
obj = super.clone();
return (Human) obj;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
System.out.println("克隆失败");
return null;
}
}
}
客户端测试类
这里就简化了。
public class PrototypeClient {
public static void main(String[] args) {
Human man = new Human();
man.setName("张三");
Human cloneMan = man.clone();
System.out.println(cloneMan.getName());
}
}
结果
当然,如果不实现Cloneable接口就会报错了,虽然Cloneable是个空接口(也被称为标识接口),但是在java里面,这个空接口就是用来判断是否支持某种操作的。
总结一下
这里实现的clone接口,其实只是浅拷贝,就是说Human里面的数组,对象等属性,比如Address 对象,拷贝成一个新的对象的时候,只是拷贝的地址,并没有生成一个新的引用。
实现深拷贝的方法:
1:让Address也实现Cloneable接口,然后在克隆Human的时候调用一下Address的clone方法。但这样优点略微复杂。
2:实现序列化,将对象写入到流中,然后再读取出来,这样对象的内容在变成字节流再转换的过程中就不存在引用的问题了。
其实就我理解来说,java里面并没有深浅拷贝的区别,毕竟都是调用Object的clone方法,只是由于嵌套了clone,导致存在深浅。
优点: 性能提高、逃避构造函数的约束。
缺点: 修改旧类很麻烦,并且类必须实现 Cloneable 接口。
网友评论