设计模式-原型模式
1、原型模式简介
定义:属于创建型模式,用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象,这种方式创建对象非常高效,根本无须知道对象创建的细节
目标:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
解决问题:运行期建立和删除实例
优点:性能提高
逃避构造函数的约束
缺点:需要为每一个类都配置一个 clone 方法
clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦
说明:原型模式的克隆分为两种,一种叫深克隆,一种叫浅克隆
2、浅克隆
定义:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址
实现:必须得实现实现 Cloneable 接口,只是复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个值都会随之变化
//原型类
public class User {
private String name;
private int date;
private int age;
public void setName(String name) {
this.name = name;
}
public void setDate(int date) {
this.date = date;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public int getDate() {
return date;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return getName()+"&&"+getDate()+"&&"+getAge();
}
}
//具体原型类
public class CloneablePrototype implements Cloneable {
private User user = new User();
public CloneablePrototype(){
user.setAge(25);
user.setDate(1995);
user.setName("CC");
System.out.println("具体原型创建成功");
}
public Object clone() throws CloneNotSupportedException {
System.out.println("具体原型复制成功");
return (CloneablePrototype)super.clone();
}
public User show(){
return user;
}
}
//测试方法
public static void main(String[] args) throws CloneNotSupportedException {
CloneablePrototype cloneablePrototype1 = new CloneablePrototype();
CloneablePrototype cloneablePrototype2 = (CloneablePrototype) cloneablePrototype1.clone();
System.out.println("clone1:"+cloneablePrototype1.show().toString());
System.out.println("clone2:"+cloneablePrototype2.show().toString());
System.out.println(cloneablePrototype1 == cloneablePrototype2);
System.out.println("===========================");
cloneablePrototype2.show().setAge(30);
System.out.println("clone1:"+cloneablePrototype1.show().toString());
System.out.println("clone2:"+cloneablePrototype2.show().toString());
System.out.println(cloneablePrototype1 == cloneablePrototype2);
}
//测试结果
具体原型创建成功
具体原型复制成功
clone1:CC&&1995&&25
clone2:CC&&1995&&25
false
===========================
clone1:CC&&1995&&30
clone2:CC&&1995&&30
false
3、深克隆
定义:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址
实现:实现 Serializable 接口,通过字节流来对数据进行复制
//原型类,实现Serializable接口
public class User extends Object implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int date;
private int age;
public void setName(String name) {
this.name = name;
}
public void setDate(int date) {
this.date = date;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public int getDate() {
return date;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return getName()+"&&"+getDate()+"&&"+getAge();
}
}
//具体原型类
public class SerializablePrototype implements Serializable {
private User user = new User();
public SerializablePrototype(){
user.setAge(21);
user.setName("NN");
user.setDate(1998);
System.out.println("具体原型创建成功");
}
public User show(){
return user;
}
public SerializablePrototype sClone(SerializablePrototype serializablePrototype){
try(ByteArrayOutputStream bOut = new ByteArrayOutputStream();
ObjectOutputStream oOut = new ObjectOutputStream(bOut)){
//oOut对象中指向写入数据存储的内存地址与bOut对象中指向数据存储的内存地址是一样的
oOut.writeObject(serializablePrototype);
try(ByteArrayInputStream bIn= new ByteArrayInputStream(bOut.toByteArray());
ObjectInputStream oIn = new ObjectInputStream(bIn)){
Object o = oIn.readObject();
System.out.println("具体原型复制成功");
return (SerializablePrototype) o;
}catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
//测试方法
public static void main(String[] args) throws CloneNotSupportedException {
SerializablePrototype s1 = new SerializablePrototype();
SerializablePrototype s2 = s1.sClone(s1);
System.out.println(s1.show().toString());
System.out.println(s2.show().toString());
System.out.println(s1 == s2);
System.out.println("============================");
s2.show().setName("QQ");
System.out.println(s1.show().toString());
System.out.println(s2.show().toString());
System.out.println(s1 == s2);
}
//测试结果
具体原型创建成功
具体原型复制成功
NN&&1998&&21
NN&&1998&&21
false
============================
NN&&1998&&21
QQ&&1998&&21
false
由此可见,s2改变之后s1的不变,说明通过字节流将s1对象指向的实际内存地址中的数据复制到另一块实际内存中,s2指向的这块新的内存地址

浙公网安备 33010602011771号