什么是原型模式
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用
使用场景
(1)类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等,通过原型拷贝避免这些消耗。
(2)通过new一个对象需要非常繁琐的数据准备或访问权限,可以使用原型模式。
(3)一个对象需要提供给其他对象访问,而且各个调用者可能需要修改其值,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝
如何解决:利用已有的一个原型对象,快速地生成和原型对象一样的实例。
实现方式
- 实现Cloneable接口
- 重写Clone方法(super.clone)
实现代码
可以看到原型模式的实现非常简单,如下
public class Test implements Cloneable{
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
相关拓展
但是Object.clone()方法有在某些场景下些问题,先看下下面的问题吧?
问题1:
- 什么是浅拷贝?什么是深拷贝?浅拷贝与深拷贝有什么区别?
浅复制造成的现象:有个Test 对象继承Cloneable接口并重写clone()f方法并且还有两个属性 int id; User user; id是基本类型,user是一个对象。
如果这时Test t1 = new Test(1,user); Test t2 = t1.clone(); 这时会获取到t1,t2两个内容一样的对象,即t1.id 等于 t2.id, t1.user 等于 t2.user;问题就出在user上,我们都知道java中基本类型是值传递,而对象传的是引用,内存地址。如果我们修改t1中user的某个属性,那么t2中的那个属性的也会随t1的修改而改变。出现这样的拷贝叫浅拷贝,不会产生这样的叫深拷贝。
2、浅拷贝有哪些实现方式
- 构造器
public User(User u){
this.id = u.id;
this.name = u.name;
//...其他属性
}
- Cloneable
public class User implements Cloneable{
public int age;
public String name; //String 也是对象,但不会像其他对象,因为String的值都是常量,即每次都是new 的一个新对象
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
3 、深拷贝有哪些实现方式
- 构造器
public class User implements Cloneable{
public User(int age, String name){
return new User(age, name);//直接重new一个User对象
}
public int age;
public String name;
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
- Cloneable
就是User对象内部的对象属性必须全部实现了Cloneable接口
public class User implements Cloneable{
public int age;
public ArrayList<String> nameList;//可能有多个别名
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}