本文讲解一下原型模式的概念并通过一个案例来进行实现。
4、原型模式
- 通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式
- 原型模式就是Java中的克隆技术,以某个对象为原型,复制出新的对象,新的对象具有原型对象的特点
- 原型模式的优点是效率高
- new出的对象的属性采用的是默认值,克隆出的对象的属性值和原型对象的一致,并且克隆出的对象不会影响原型对象。
原型模式的实现:
- Cloneable接口和clone方法
- 原型模式中实现最困难的地方就是内存复制操作,还好Java中提供了clone()方法替我们做了绝大部门事情
4.1、浅克隆
- 被复制的对象的所有变量与原来的变量相同,但是所有的对象的引用仍然指向原来的对象
4.2、 深克隆
- 深克隆把引用的变量指向复制过的新对象,不是原有的被引用的对象
- 基本数据类型和String能够自动实现深度克隆(值的复制)
4.3 代码实现
Sheep类为浅克隆,Sheep2为深克隆
public class Sheep implements Cloneable , Serializable {
private String name;
private Date birthday;
public Sheep() {
}
public Sheep(String name, Date birthday) {
this.name = name;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();//直接调用String对象的clone()方法
return obj;
}
}
public class Sheep2 implements Cloneable{
private String name;
private Date birthday;
public Sheep2() {
}
public Sheep2(String name, Date birthday) {
this.name = name;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();//直接调用String对象的clone()方法
//添加如下代码,实现深克隆
Sheep2 s= (Sheep2)obj;
s.birthday = (Date) this.birthday.clone();
return obj;
}
}
客户端调用测试
/**
* 测试浅克隆
* @author tqq
* @date 2021-04-26-15:45
*/
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Date date = new Date(12423423543L);
Sheep s1 = new Sheep("少利",date);
Sheep s2 = (Sheep) s1.clone();
date.setTime(1243242343243L);
System.out.println(s1.getBirthday().getTime());//1243242343243
System.out.println(s1.getName());
System.out.println(s2.getBirthday().getTime());//1243242343243
System.out.println(s2.getName());
}
}
/**
* 测试深克隆
* @author tqq
* @date 2021-04-26-15:45
*/
public class Client2 {
public static void main(String[] args) throws CloneNotSupportedException {
Date date = new Date(12423423543L);
Sheep2 s1 = new Sheep2("少利",date);
Sheep2 s2 = (Sheep2) s1.clone();
date.setTime(1243242343243L);
System.out.println(s1.getBirthday());//Mon May 25 17:05:43 CST 2009
System.out.println(s1.getName());
System.out.println(s2.getBirthday());//Mon May 25 02:57:03 CST 1970
System.out.println(s2.getName());
}
}
4.4、 new()方式创建对象VS克隆方式创建对象
/**
* 测试普通new方式对象和clone方式创建对象的效率差异
* 如果需要短时间创建大量对象并且new的过程比较耗时,则可以考虑使用原型模式
* @author tqq
* @date 2021-04-27-10:21
*/
public class Client4 {
public static void main(String[] args) throws CloneNotSupportedException {
testNew(100);//1564
testClone(100000000);//703
}
public static void testNew(int size){
long start = System.currentTimeMillis();
for (int i = 0; i <size; i++) {
Laptop laptop = new Laptop();
}
long end = System.currentTimeMillis();
System.out.println("new的方式创建耗时:"+(end-start));
}
public static void testClone(int size) throws CloneNotSupportedException {
long start = System.currentTimeMillis();
Laptop laptop = new Laptop();
for (int i = 0; i <size; i++) {
Laptop l = (Laptop) laptop.clone();
}
long end = System.currentTimeMillis();
System.out.println("clone的方式创建耗时:"+(end-start));
}
}
class Laptop implements Cloneable{
public Laptop() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();//直接调用String对象的clone()方法
return obj;
}
}
4.5、 应用场景
- 原型模式一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者
- Spring中的bean的创建实际就是两种:单例模式和原型模式(原型模式和工厂模式要搭建起来)