原型模式:
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
类图:
原型模式主要用于对象的复制,其核心是Prototype类。JAVA中Prototype类具备以下两个条件:
- 实现Cloneable接口。JAVA中有一个Cloneable接口,作用是通知虚拟机可以安全的在实现了此接口的类上使用clone方法。在JAVA中,只有实现了Cloneable才能使用clone方法进行拷贝,否则会抛出CloneNotSupportedException异常。
- 重写Clone方法。Clone方法是Object中的方法,作用是返回对象的一个拷贝,但其作用域一般是protected,一般的类无法调用,因此Prototype需要把clone方法改成public修饰。
浅复制与深复制:
现在已要写一份简历类,简历包括姓名,性别,包括一个工作经历类,工作经历类包括工作时间和公司信息。然后拷贝简历三份。
浅赋值代码如下:
// 工作经历类
public class WorkExperience {
public String workDate;
public String company;
public void setWorkDate(String workDate){
this.workDate = workDate;
}
public String getWorkDate(){
return workDate;
}
public void setCompany(String company){
this.company = company;
}
public String getCompany(){
return company;
}
}
// 简历类
private String name;
private String age;
private String sex;
private WorkExperience workExperience;
public Resume(String name){
this.name = name;
workExperience = new WorkExperience();
}
// 设置个人信息
public void SetPersonalInfo(String sex,
String age){
this.age = age;
this.sex = sex;
}
// 设置工作经历
public void SetWorkExperience(String workDate,
String company){
workExperience.workDate = workDate;
workExperience.company = company;
}
//打印
public void Dispaly(){
System.out.println(name + " " + age+" "+ " "+sex );
System.out.println("工作经历:" + workExperience.workDate + " "+
workExperience.company);
}
// 重写clone方法
@Override
public Resume clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
Resume resume = null;
try{
resume = (Resume)super.clone();
}catch (CloneNotSupportedException e) {
// TODO: handle exception
e.printStackTrace();
}
return resume;
}
}
// 客户端
private String name;
private String age;
private String sex;
private WorkExperience workExperience;
public Resume(String name){
this.name = name;
workExperience = new WorkExperience();
}
// 设置个人信息
public void SetPersonalInfo(String sex,
String age){
this.age = age;
this.sex = sex;
}
// 设置工作经历
public void SetWorkExperience(String workDate,
String company){
workExperience.workDate = workDate;
workExperience.company = company;
}
//打印
public void Dispaly(){
System.out.println(name + " " + age+" "+ " "+sex );
System.out.println("工作经历:" + workExperience.workDate + " "+
workExperience.company);
}
// 重写clone方法
@Override
public Resume clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
Resume resume = null;
try{
resume = (Resume)super.clone();
}catch (CloneNotSupportedException e) {
// TODO: handle exception
e.printStackTrace();
}
return resume;
}
}
以上代码叫做浅复制,被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。也就是说,代码中“工作经历”虽然在resumeA,resumeB,resumeC中分别有复制,但是这三份简历中的引用都指向同一个对象的。
将浅复制改为深复制,代码如下:
// 工作经历类
public class WorkExperience implements Cloneable{
public String workDate;
public String company;
public void setWorkDate(String workDate){
this.workDate = workDate;
}
public String getWorkDate(){
return workDate;
}
public void setCompany(String company){
this.company = company;
}
public String getCompany(){
return company;
}
// 重写clone方法
@Override
public WorkExperience clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
WorkExperience workExperience = null;
try{
workExperience = (WorkExperience) super.clone();
}catch (CloneNotSupportedException e) {
// TODO: handle exception
e.printStackTrace();
}
return workExperience;
}
}
// 简历类
public class Resume implements Cloneable {
private String name;
private String age;
private String sex;
private WorkExperience workExperience;
public Resume(String name){
this.name = name;
workExperience = new WorkExperience();
}
private Resume(WorkExperience workExperience){
this.workExperience = workExperience;
}
// 设置个人信息
public void SetPersonalInfo(String sex,
String age){
this.age = age;
this.sex = sex;
}
// 设置工作经历
public void SetWorkExperience(String workDate,
String company){
workExperience.workDate = workDate;
workExperience.company = company;
}
//打印
public void Dispaly(){
System.out.println(name + " " + age+" "+ " "+sex );
System.out.println("工作经历:" + workExperience.workDate + " "+
workExperience.company);
}
// 重写clone方法
@Override
public Resume clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
Resume resume = new Resume(this.workExperience);
resume.name = this.name;
resume.age = this.age;
resume.sex = this.sex;
return resume;
}
}
// 客户端
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Resume resumeA = new Resume("大磊");
resumeA.SetPersonalInfo("男", "22");
resumeA.SetWorkExperience("2016-2017", "bbk");
resumeA.Dispaly();
Resume resumeB = null;
Resume resumeC = null;
try {
resumeB = (Resume)resumeA.clone();
resumeC = (Resume)resumeA.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
resumeB.Dispaly();
resumeC.Dispaly();
}
}
深复制把引用对象的变量指向复制过的新对象,而不是原有的引用对象。
分析:
使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。