一、原型模式介绍
原型模式(Prototype)是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。
原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节。
使用前提:
- 实现
Cloneable接口。(运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。)- 重写
Object类中的clone()方法。(返回对象的一个拷贝)两种拷贝方式:
- 浅拷贝
- 深拷贝
二、浅拷贝
2.1 示例关系:
2.2 代码实现:
/* *
* 定义一个Dog类,实现Cloneable接口。
* 有带参构造方法。
* 重写toString()、clone()方法。
*/
class Dog implements Cloneable {
String name;
int age;
Dog friend;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
protected Object clone() {
Object shallowCopyObj = null;
try {
shallowCopyObj = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return shallowCopyObj;
}
}
public class PrototypeShallowCopy {
public static void main(String[] args) {
Dog tom = new Dog("tom", 2);
// 为成员的对象类型赋值。
tom.friend = new Dog("jack", 3);
// 使用原型模式对对象进行克隆。
Dog tom1 = (Dog) tom.clone();
Dog tom2 = (Dog) tom.clone();
System.out.println(" dog_info: " + tom + " friend_hashCode: " + tom.friend.hashCode());
System.out.println(" dog_info: " + tom1 + " friend_hashCode: " + tom1.friend.hashCode());
System.out.println(" dog_info: " + tom2 + " friend_hashCode: " + tom2.friend.hashCode());
// dog_info: Dog{name='tom', age=2} friend_hashCode: 968514068
// dog_info: Dog{name='tom', age=2} friend_hashCode: 968514068
// dog_info: Dog{name='tom', age=2} friend_hashCode: 968514068
// 引用对象类型地址值一样。
}
}
2.3 方式说明:
默认情况下原型模式使用的是浅拷贝。
若成员变量是基本数据类型则直接进行值传递;若是某个类对象、某个数组等则将成员变量的内存地址复制给一个新的对象,实际上指向的都是同一实例。
该拷贝方式下,修改一个对象的成员变量会影响另一个对象的成员变量值。
三、深拷贝
3.1 示例关系:
3.2 代码实现:
/* *
* 定义一个Cat类,实现Cloneable、Serializable接口。
* 有带参构造方法。
* 重写toString()、clone()方法。
*/
class Cat implements Cloneable, Serializable {
String name;
int age;
Cat friend;
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
/* *
* 通过序列化-反序列化方式实现。
*/
@Override
protected Object clone() {
// 创建字节输入输出流、对象输入输出流。
ByteArrayOutputStream bos = null;
ByteArrayInputStream bis = null;
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
Cat deepCopyObj = null;
try {
// 序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
//当前对象以流形式输出
oos.writeObject(this);
// 反序列化。
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
deepCopyObj = (Cat) ois.readObject();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 资源释放。
try {
assert ois != null;
ois.close();
bis.close();
oos.close();
bos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return deepCopyObj;
}
}
public class PrototypeDeepCopy {
public static void main(String[] args) {
Cat tom = new Cat("tom", 2);
tom.friend = new Cat("jack", 3);
Cat tom1 = (Cat) tom.clone();
Cat tom2 = (Cat) tom.clone();
System.out.println(" cat_info: " + tom + " friend_hashCode: " + tom.friend.hashCode());
System.out.println(" cat_info: " + tom1 + " friend_hashCode: " + tom1.friend.hashCode());
System.out.println(" cat_info: " + tom2 + " friend_hashCode: " + tom2.friend.hashCode());
// cat_info: Cat{name='tom', age=2} friend_hashCode: 1166726978
// cat_info: Cat{name='tom', age=2} friend_hashCode: 1824835605
// cat_info: Cat{name='tom', age=2} friend_hashCode: 981661423
// 引用对象类型都是独立的。
}
}
3.3 方式说明:
复制对象的所有基本数据类型的成员变量值。
为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。(即:独立且完整的方式进行拷贝)
四、总结:
使用原型模式简化了对象的重复创建过程。
两种方式区别:
深拷贝就是对象引用和对象一起给复制了一遍,实现了这个物理上的完全隔离。
浅拷贝则是简单的复制了对象的引用,实质上还是指向同一个对象。
浅拷贝会带来数据安全方面的隐患,深拷贝相比于浅拷贝速度较慢并且花销较大。
工作原理: 通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即对象
.clone()。需要注意: 原型模式(动态创建对象)与单例模式(只允许单个实例存在)是冲突的。
五 、结束语
“-------怕什么真理无穷,进一寸有一寸的欢喜。”
微信公众号搜索:饺子泡牛奶。