这里写目录标题
原型模式对象克隆浅拷贝深拷贝
原型模式
基本介绍
原型模式
(Prototype模式
)是指:用原型实例指定创建对象的种类,并且通过拷
贝这些原型,创建新的对象
原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象, 无需知道如何创建的细节
工作原理是
:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建
的对象通过请求原型对象拷贝它们自己来实施创建,即 对象
.clone()
形象的理解:孙大圣拔出猴毛, 变出其它孙大圣
关键代码:
1、实现克隆操作,在 JAVA 继承 Cloneable,重写
clone(),在
.NET 中可以使用 Object 类的
MemberwiseClone() 方法来实现对象的浅拷贝或通过序列化的方式来实现深拷贝。
2、原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些
"易变类"拥有稳定的接口。
应用实例:
1、细胞分裂。
2、JAVA 中的 Object
clone() 方法。
优点:
1、性能提高。
2、逃避构造函数的约束。
缺点:
1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
2、必须实现 Cloneable 接口。
使用场景:
1、资源优化场景。
2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
3、性能和安全要求的场景。
4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
5、一个对象多个修改者的场景。
6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
7、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与 Java 融为浑然一体,大家可以随手拿来使用。
注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。
对象克隆
1) 优点是比较好理解,简单易操作。
2) 在创建新的对象时,总是需要重新获取原始对象的属性,如果创建的对象比较复杂
时,效率较低
3) 总是需要重新初始化对象,而不是动态地获得对象运行时的状态
, 不够灵活
package prototype
;
public class Client {
public static void main(String
[] args
) {
Sheep sheep
= new Sheep("tom", 1, "红色");
Sheep sheep2
= new Sheep(sheep
.getName(), sheep
.getAge(), sheep
.getColor());
Sheep sheep3
= new Sheep(sheep
.getName(), sheep
.getAge(), sheep
.getColor());
Sheep sheep4
= new Sheep(sheep
.getName(), sheep
.getAge(), sheep
.getColor());
Sheep sheep5
= new Sheep(sheep
.getName(), sheep
.getAge(), sheep
.getColor());
System
.out
.println(sheep
);
System
.out
.println(sheep2
);
System
.out
.println(sheep3
);
System
.out
.println(sheep4
);
System
.out
.println(sheep5
);
}
}
package prototype
;
public class Sheep {
private String name
;
private int age
;
private String color
;
public Sheep(String name
, int age
, String color
) {
super();
this.name
= name
;
this.age
= age
;
this.color
= color
;
}
public String
getName() {
return name
;
}
public void setName(String name
) {
this.name
= name
;
}
public int getAge() {
return age
;
}
public void setAge(int age
) {
this.age
= age
;
}
public String
getColor() {
return color
;
}
public void setColor(String color
) {
this.color
= color
;
}
@Override
public String
toString() {
return "Sheep [name=" + name
+ ", age=" + age
+ ", color=" + color
+ "]";
}
}
浅拷贝
1) 对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将
该属性值复制一份给新的对象。
2) 对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类
的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内
存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个
实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成
员变量值
3) 前面我们克隆羊就是浅拷贝
4) 浅拷贝是使用默认的
clone()方法来实现
sheep
= (Sheep
) super
.clone();
package prototype
.improve
;
public class Sheep implements Cloneable {
private String name
;
private int age
;
private String color
;
private String address
= "蒙古羊";
public Sheep friend
;
public Sheep(String name
, int age
, String color
) {
super();
this.name
= name
;
this.age
= age
;
this.color
= color
;
}
public String
getName() {
return name
;
}
public void setName(String name
) {
this.name
= name
;
}
public int getAge() {
return age
;
}
public void setAge(int age
) {
this.age
= age
;
}
public String
getColor() {
return color
;
}
public void setColor(String color
) {
this.color
= color
;
}
@Override
public String
toString() {
return "Sheep [name=" + name
+ ", age=" + age
+ ", color=" + color
+ ", address=" + address
+ "]";
}
@Override
protected Object
clone() {
Sheep sheep
= null
;
try {
sheep
= (Sheep
)super.clone();
} catch (Exception e
) {
System
.out
.println(e
.getMessage());
}
return sheep
;
}
}
package prototype
.improve
;
public class Client {
public static void main(String
[] args
) {
System
.out
.println("原型模式完成对象的创建");
Sheep sheep
= new Sheep("tom", 1, "白色");
sheep
.friend
= new Sheep("jack", 2, "黑色");
Sheep sheep2
= (Sheep
)sheep
.clone();
Sheep sheep3
= (Sheep
)sheep
.clone();
Sheep sheep4
= (Sheep
)sheep
.clone();
Sheep sheep5
= (Sheep
)sheep
.clone();
System
.out
.println("sheep2 =" + sheep2
+ "sheep2.friend=" + sheep2
.friend
.hashCode());
System
.out
.println("sheep3 =" + sheep3
+ "sheep3.friend=" + sheep3
.friend
.hashCode());
System
.out
.println("sheep4 =" + sheep4
+ "sheep4.friend=" + sheep4
.friend
.hashCode());
System
.out
.println("sheep5 =" + sheep5
+ "sheep5.friend=" + sheep5
.friend
.hashCode());
}
}
深拷贝
1) 复制对象的所有基本数据类型的成员变量值
2) 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变
量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对
整个对象进行拷贝
3) 深拷贝实现方式
1:重写clone方法来实现深拷贝
4) 深拷贝实现方式
2:通过对象序列化实现深拷贝
(推荐
)
package prototype
.deepclone
;
import java
.io
.Serializable
;
public class DeepCloneableTarget implements Serializable, Cloneable
{
private static final long serialVersionUID
= 1L
;
private String cloneName
;
private String cloneClass
;
DeepCloneableTarget(String cloneName
, String cloneClass
) {
this.cloneName
= cloneName
;
this.cloneClass
= cloneClass
;
}
@Override
protected Object
clone() throws CloneNotSupportedException
{
return super.clone();
}
}
package prototype
.deepclone
;
import java
.io
.ByteArrayInputStream
;
import java
.io
.ByteArrayOutputStream
;
import java
.io
.ObjectInputStream
;
import java
.io
.ObjectOutputStream
;
import java
.io
.Serializable
;
public class DeepProtoType implements Serializable, Cloneable
{
public String name
;
public DeepCloneableTarget deepCloneableTarget
;
public DeepProtoType() {
super();
}
@Override
protected Object
clone() throws CloneNotSupportedException
{
Object deep
= super.clone();
DeepProtoType deepProtoType
= (DeepProtoType
)deep
;
deepProtoType
.deepCloneableTarget
= (DeepCloneableTarget
)deepCloneableTarget
.clone();
return deepProtoType
;
}
public Object
deepClone() {
ByteArrayOutputStream bos
= null
;
ObjectOutputStream oos
= null
;
ByteArrayInputStream bis
= null
;
ObjectInputStream ois
= null
;
try {
bos
= new ByteArrayOutputStream();
oos
= new ObjectOutputStream(bos
);
oos
.writeObject(this);
bis
= new ByteArrayInputStream(bos
.toByteArray());
ois
= new ObjectInputStream(bis
);
DeepProtoType copyObj
= (DeepProtoType
)ois
.readObject();
return copyObj
;
} catch (Exception e
) {
e
.printStackTrace();
return null
;
} finally {
try {
bos
.close();
oos
.close();
bis
.close();
ois
.close();
} catch (Exception e2
) {
System
.out
.println(e2
.getMessage());
}
}
}
}
package prototype
.deepclone
;
public class Client {
public static void main(String
[] args
) throws Exception
{
DeepProtoType p
= new DeepProtoType();
p
.name
= "宋江";
p
.deepCloneableTarget
= new DeepCloneableTarget("大牛", "小牛");
DeepProtoType p2
= (DeepProtoType
) p
.deepClone();
System
.out
.println("p.name=" + p
.name
+ "p.deepCloneableTarget=" + p
.deepCloneableTarget
.hashCode());
System
.out
.println("p2.name=" + p
.name
+ "p2.deepCloneableTarget=" + p2
.deepCloneableTarget
.hashCode());
}
}