原型模式(Prototype Pattern)属于创建型模式,它允许一个对象通过复制自身来创建一个新的对象,而无需通过构造函数创建。这种模式特别适用于创建复杂对象时,避免构造函数的复杂性,同时提高性能。以下是关于原型模式的详细介绍、JAVA代码实现、运行结果及注释。
一、原型模式概述
定义
原型模式:用原型实例指定创建对象的种类,并通过复制这些原型创建新的对象。
主要角色
- (1)抽象原型(Prototype)角色:定义具有克隆自身方法的接口。
- (2)具体原型(ConcretePrototype)角色:实现抽象原型接口,实现克隆自身的方法。
- (3)客户端(Client)角色:通过调用具体原型的克隆方法来创建新对象。
优点
- (1)提高性能:通过复制现有对象,避免创建对象的初始化过程,提高性能。
- (2)简化创建过程:无需通过构造函数创建对象,简化创建过程。
- (3)动态创建对象:可根据需求动态地创建对象,提高代码的灵活性。
缺点
- (1)深拷贝和浅拷贝:在实现克隆方法时,需要考虑深拷贝和浅拷贝的问题,增加实现难度。
- (2)违背开闭原则:如果原型对象发生变化,需要修改克隆方法,可能导致原有代码受到影响。
二、JAVA代码实现
以下是一个简单的原型模式实现,以一个简历类为例:
java
// 抽象原型接口,定义克隆方法
interface Resume extends Cloneable {
Resume clone();
void display();
}
// 具体原型角色,实现抽象原型接口
class ConcreteResume implements Resume {
// 简历属性
private String name;
private String age;
private String experience;
// 构造函数
public ConcreteResume(String name, String age, String experience) {
this.name = name;
this.age = age;
this.experience = experience;
}
// 实现克隆方法
@Override
public Resume clone() {
ConcreteResume resume = null;
try {
// 调用Object类的clone方法实现浅拷贝
resume = (ConcreteResume) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return resume;
}
// 显示简历信息
@Override
public void display() {
System.out.println("姓名:" + name);
System.out.println("年龄:" + age);
System.out.println("经历:" + experience);
}
// 省略getter和setter方法
}
// 客户端角色,测试原型模式
public class Client {
public static void main(String[] args) {
// 创建原型对象
ConcreteResume resume = new ConcreteResume("张三", "25", "某公司实习");
// 通过克隆方法创建新对象
ConcreteResume resume1 = (ConcreteResume) resume.clone();
ConcreteResume resume2 = (ConcreteResume) resume.clone();
// 显示新对象信息
resume1.display();
System.out.println("-----------");
resume2.display();
}
}
运行结果:
java
姓名:张三
年龄:25
经历:某公司实习
-----------
姓名:张三
年龄:25
经历:某公司实习
以上代码展示了原型模式的基本实现。在实际应用中,可以根据需求对原型对象进行扩展,实现深拷贝等功能。需要注意的是,原型模式适用于创建复杂对象,如果创建的对象较为简单,使用构造函数即可满足需求时,原型模式可能并不适用。下面,我们将继续深入探讨原型模式,并完成深拷贝的实现。
深拷贝与浅拷贝
在上面的例子中,我们实现了浅拷贝。浅拷贝只是复制了对象的所有基本类型的成员变量值,以及所有引用类型成员变量的引用值,而没有复制引用的对象本身。如果原型对象中包含引用类型成员变量,且这些引用指向的对象也需要被复制,那么就需要实现深拷贝。
实现深拷贝
要实现深拷贝,可以通过以下几种方式:
-
重写clone方法:在clone方法中,对引用类型成员变量也进行克隆。
-
通过序列化:先将对象序列化到流中,然后再从流中反序列化出来,得到一个全新的对象。 下面我们使用第一种方式来实现深拷贝:
java
import java.io.Serializable;
// 抽象原型接口
interface Resume extends Cloneable, Serializable {
Resume clone();
void display();
}
// 具体原型角色
class ConcreteResume implements Resume {
private String name;
private String age;
private WorkExperience workExperience; // 引用类型成员变量
public ConcreteResume(String name, String age, WorkExperience workExperience) {
this.name = name;
this.age = age;
this.workExperience = workExperience;
}
@Override
public Resume clone() {
ConcreteResume resume = null;
try {
resume = (ConcreteResume) super.clone();
// 对引用类型成员变量进行深拷贝
resume.workExperience = (WorkExperience) this.workExperience.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return resume;
}
@Override
public void display() {
System.out.println("姓名:" + name);
System.out.println("年龄:" + age);
System.out.println("工作经历:" + workExperience.getCompany() + " " + workExperience.getDuration());
}
// 省略getter和setter方法
}
// 工作经历类
class WorkExperience implements Cloneable, Serializable {
private String company;
private String duration;
public WorkExperience(String company, String duration) {
this.company = company;
this.duration = duration;
}
@Override
public WorkExperience clone() {
WorkExperience workExperience = null;
try {
workExperience = (WorkExperience) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return workExperience;
}
// 省略getter和setter方法
public String getCompany() {
return company;
}
public String getDuration() {
return duration;
}
}
// 客户端角色
public class Client {
public static void main(String[] args) {
WorkExperience workExperience = new WorkExperience("某公司", "2019-2021");
ConcreteResume resume = new ConcreteResume("张三", "25", workExperience);
ConcreteResume resume1 = (ConcreteResume) resume.clone();
ConcreteResume resume2 = (ConcreteResume) resume.clone();
// 修改工作经历,以验证深拷贝
workExperience.setCompany("新公司");
workExperience.setDuration("2022-至今");
resume1.display();
System.out.println("-----------");
resume2.display();
}
}
运行结果:
java
姓名:张三
年龄:25
工作经历:某公司 2019-2021
-----------
姓名:张三
年龄:25
工作经历:某公司 2019-2021
在上面的代码中,我们添加了一个WorkExperience
类,并在ConcreteResume
类中引入了该类的实例作为成员变量。在ConcreteResume
的clone
方法中,我们对workExperience
成员变量也进行了克隆,从而实现了深拷贝。
原型模式的优缺点
优点
-
提高性能:当创建新的对象实例较为复杂且耗时时,原型模式可以简化对象的创建过程,提高性能。
-
简化创建过程:通过复制现有实例来创建新实例,避免了复杂的构造函数调用。
-
保护性拷贝:原型模式可以在运行时保护性地拷贝对象,避免外部直接修改对象状态。
缺点
-
深拷贝实现复杂:如果对象之间存在复杂的引用关系,实现深拷贝可能会比较困难。
-
违背开闭原则:如果原型对象发生变化,则所有通过克隆创建的对象都需要进行相应的修改。
总结
原型模式通过复制现有对象来创建新对象,适用于创建复杂对象的情况。在实现原型模式时,需要注意浅拷贝和深拷贝的区别,并根据实际需求选择合适的拷贝方式。通过上述代码示例,我们可以看到原型模式在Java中的具体实现,以及如何通过深拷贝来保持对象间的独立性。