文章目录
- 一、定义
- 二、使用场景
- 三、代码样例
-
- 1.类图
- 2.简历实体类
- 3.实体工作经验
- 4.客户端类
- 4.输出
- 四、优缺点
- 五、两种实现方式:浅拷贝和深拷贝
-
- 1.浅拷贝
- 2.深拷贝
- 结尾
一、定义
原型模式使用原型实例指定创建对象的类型,并通过复制原型对象创建新对象。原型模式的本质是一种克隆对象的方法,其核心是重写Object中的clone调用该方法可以在内存中复制对象。
Java提供标记接口——Cloneable,在接口中完成标记JVM有这个标记的对象可能会被复制。如果接口没有实现,克隆对象将被抛出CloneNotSupportedException异常。
二、使用场景
- 当一个系统应该独立于其产品的创建、构成和表达时,应该使用原型模式
- 例子类是指定运行时间,如动态装载
- 为了避免创建与产品级平行的工厂级别
- 当一个类的例子只有几个不同状态组合中的一个时。建立相应数量的原型和克隆原型可能比每次使用合适状态的手动实例原型更方便。
三、代码样例
1.类图
简历复制通过原型模式实现
- 抽象原型(Prototype)角色:规定了具体原型对象必须实现的接口(如果要提供深度复制,则必须实现clone的规定)
- 具体原型(ConcretePrototype):由抽象原型衍生而来,是客户程序使用的对象,即复制对象,需要实现抽象原型角色所需的接口。
- 客户(Client)角色:使用原型对象的客户程序
2.简历实体类
/** * 简历类 */ public class Resume implements Cloneable, Serializable {
private static final long serialVersionUID = -4410449301166191440L; private String name; private String gender; private int age; /** * 引用工作经验对象,用于演示深度拷贝和浅度拷贝 */ private WorkExperience workExperience; public Resume() {
// 简历类实例化时,工作经验类实例化 workExperience = new WorkExperience(); } public void display() {
System.out.println(this.getName()
+
" "
+
this
.
getGender
(
)
+
" "
+
this
.
getAge
(
)
+
"\n工作经历: "
+
this
.
getWorkExperience
(
)
.
getWorkDate
(
)
+
" "
+
this
.
getWorkExperience
(
)
.
getWorkCompany
(
)
)
;
}
@Override
protected
Object
clone
(
)
throws
CloneNotSupportedException
{
return
super
.
clone
(
)
;
}
// 通过对象序列化,实现深度拷贝
public
Object
deepClone
(
)
throws
IOException
,
ClassNotFoundException
{
// 将对象写入流内
ByteArrayOutputStream bos
=
new
ByteArrayOutputStream
(
)
;
ObjectOutputStream oos
=
new
ObjectOutputStream
(bos
)
; oos
.
writeObject
(
this
)
;
// 从流内读出对象
ObjectInputStream ois
=
new
ObjectInputStream
(
new
ByteArrayInputStream
( bos
.
toByteArray
(
)
)
)
;
return ois
.
readObject
(
)
;
}
public
String
getName
(
)
{
return name
;
}
public
Resume
setName
(
String name
)
{
this
.name
= name
;
return
this
;
}
public
String
getGender
(
)
{
return gender
;
}
public
Resume
setGender
(
String gender
)
{
this
.gender
= gender
;
return
this
;
}
public
int
getAge
(
)
{
return age
;
}
public
Resume
setAge
(
int age
)
{
this
.age
= age
;
return
this
;
}
public
WorkExperience
getWorkExperience
(
)
{
return workExperience
;
}
public
void
setWorkExperience
(
String workDate
,
String workCompany
)
{
workExperience
.
setWorkDate
(workDate
)
; workExperience
.
setWorkCompany
(workCompany
)
;
}
}
3.工作经历实体类
/** * 工作经历类,为演示深度拷贝和浅度拷贝而用 */
public class WorkExperience implements Serializable {
private static final long serialVersionUID = 1L;
private String workDate;
private String workCompany;
public String getWorkDate() {
return workDate;
}
public WorkExperience setWorkDate(String workDate) {
this.workDate = workDate;
return this;
}
public String getWorkCompany() {
return workCompany;
}
public WorkExperience setWorkCompany(String workCompany) {
this.workCompany = workCompany;
return this;
}
}
4.客户端类
/** * 原型模式客户端 演示深度拷贝和浅度拷贝 */
public class PrototypeClient {
public static void shallowCopy() throws CloneNotSupportedException {
Resume aResume = new Resume();
aResume.setName("大鸟 ").setGender("男 ").setAge(25);
aResume.setWorkExperience("1999-2002, ", "XX公司");
Resume bResume = (Resume) aResume.clone();
bResume.setWorkExperience("1999-2002, ", "YY公司");
Resume cResume = (Resume) aResume.clone();
cResume.setWorkExperience("1999-2002, ", "ZZ公司");
System.out.println(">>>>>>浅度拷贝:");
aResume.display();
bResume.display();
cResume.display();
}
public static void deepCopy() throws CloneNotSupportedException,
ClassNotFoundException, IOException {
Resume aResume = new Resume();
aResume.setName("大鸟 ").setGender("男 ").setAge(25);
aResume.setWorkExperience("1999-2002, ", "XX公司");
Resume bResume = (Resume) aResume.deepClone();
bResume.setWorkExperience("1999-2002, ", "YY公司");
Resume cResume = (Resume) aResume.deepClone();
cResume.setWorkExperience("1999-2002, ", "ZZ公司");
System.out.println(">>>>>>深度拷贝:");
aResume.display();
bResume.display();
cResume.display();
}
public static void main(String[] args) throws CloneNotSupportedException,
ClassNotFoundException, IOException {
// 浅度拷贝
shallowCopy();
System.out.println("==================================");
// 深度拷贝
deepCopy();
}
}
4.输出
四、优缺点
- Java 自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。
- 可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。
- 需要为每一个类都配置一个 clone 方法
- clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
- 当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆、浅克隆需要运用得当。
五、两种实现方式:浅拷贝与深拷贝
1.浅拷贝
被拷贝对象的所有变量都含有与原对象相同的值,而且对其他对象的引用仍然是指向原来的对象。即浅拷贝只负责当前对象实例,对引用的对象不做拷贝。
2.深拷贝
被拷贝对象的所有的变量都含有与原来对象相同的值,除了引用其他对象的变量。引用其他对象的变量将指向一个被拷贝的新对象,而不再是原有被引用对象。即深拷贝把要拷贝的对象所引用的对象也都拷贝了一次。
深拷贝要深入到多少层,是一个不确定的问题。在决定以深拷贝的方式拷贝一个对象的时候,必须决定对间接拷贝的对象是采取浅拷贝还是深拷贝还是继续采用深拷贝。因此,在采取深拷贝时,需要决定多深才算深。此外,在深拷贝的过程中,很可能会出现循环引用的问题。
结尾
- 感谢大家的耐心阅读,如有建议请私信或评论留言。
- 如有收获,劳烦支持,关注、点赞、评论、收藏均可,博主会经常更新,与大家共同进步