原型模式
是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
优点: 1、性能提高。 2、逃避构造函数的约束。
缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable 接口。
注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。
浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。
具体实现
原型类
package com.chenpt.designModel.prototypeModel;
import java.io.Serializable;
/**
* @Author: chenpengtao
* @Description: 简历
* @Date: created in 2018/8/1
* @Modified By:
*/
public class Resume implements Cloneable,Serializable{
private static final long serialVersionUID = 1L;
private String name;
private String sex;
private String age;
Resume(String name,String sex,String age){
this.name=name;
this.sex=sex;
this.age=age;
}
/**
* 设置个人信息
* @param sex
* @param age
*/
public void setPersonInfo(String sex,String age){
this.sex=sex;
this.age=age;
}
//描述
public void dispaly(){
System.out.println("姓名:"+name+"\t年龄:"+age+"\t性别:"+sex);
}
public Object clone(){
try {
Resume resume = (Resume)super.clone();
return resume;
}catch (Exception e){
return null;
}
}
}
客户端
package com.chenpt.designModel.prototypeModel;
/**
* @Author: chenpengtao
* @Description:
* @Date: created in 2018/8/1
* @Modified By:
*/
public class MainTest {
public static void main(String[] args){
Resume resume = new Resume("大鸟","男","25");
Resume resume2 = (Resume)resume.clone();
resume2.setPersonInfo("男","26");
resume.dispaly();
resume2.dispaly();
}
}
//结果
姓名:大鸟 年龄:25 性别:男
姓名:大鸟 年龄:26 性别:男
如上代码基本实现了一个原型模式示例:
浅复制与深复制
现在需求改了–我们需要新加入工作经历,那么修改上述代码
新加入工作类
package com.chenpt.designModel.prototypeModel;
/**
* @Author: chenpengtao
* @Description: 工作经历
* @Date: created in 2018/8/1
* @Modified By:
*/
public class WorkExperience{
private String workDate;
private String company;
public WorkExperience(String workDate,String company){
this.workDate=workDate;
this.company=company;
}
public WorkExperience(){}
public String getWorkDate() {
return workDate;
}
public void setWorkDate(String workDate) {
this.workDate = workDate;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
}
在个人信息那边引入工作类
package com.chenpt.designModel.prototypeModel;
import java.io.Serializable;
/**
* @Author: chenpengtao
* @Description: 简历
* @Date: created in 2018/8/1
* @Modified By:
*/
public class Resume implements Cloneable,Serializable{
private static final long serialVersionUID = 1L;
private String name;
private String sex;
private String age;
private WorkExperience workExperience;
Resume(String name,String sex,String age){
this.name=name;
this.sex=sex;
this.age=age;
this.workExperience=new WorkExperience();
}
/**
* 设置个人信息
* @param sex
* @param age
*/
public void setPersonInfo(String sex,String age){
this.sex=sex;
this.age=age;
}
/**
* 设置工作经历
* @param workDate
* @param company
*/
public void setWorkExperience(String workDate, String company){
this.workExperience.setWorkDate(workDate);
this.workExperience.setCompany(company);
}
//描述
public void dispaly(){
System.out.println("姓名:"+name+"\t年龄:"+age+"\t性别:"+sex);
System.out.println("工作经历:"+workExperience.getWorkDate()+"\t"+workExperience.getCompany());
}
public Object clone(){
try {
Resume resume = (Resume)super.clone();
return resume;
}catch (Exception e){
return null;
}
}
}
客户端
package com.chenpt.designModel.prototypeModel;
/**
* @Author: chenpengtao
* @Description:
* @Date: created in 2018/8/1
* @Modified By:
*/
public class MainTest {
public static void main(String[] args){
Resume resume = new Resume("大鸟","男","25");
resume.setWorkExperience("2015-2016","南京工作");
Resume resume2 = (Resume)resume.clone();
resume2.setPersonInfo("男","26");
resume2.setWorkExperience("2016-2018","上海工作");
resume.dispaly();
resume2.dispaly();
}
}
//执行结果
姓名:大鸟 年龄:25 性别:男
工作经历:2016-2018 上海工作
姓名:大鸟 年龄:26 性别:男
工作经历:2016-2018 上海工作
咦!!!什么情况???怎么工作经历显示的是最后一次设置的值啊?
不要慌 问题不大。这是由于浅表复制导致的结果,对于值类型 克隆没问题,但对于引用类型来说,就只是复制了引用,引用的对象还是原来对象的地址,所以才有上述结果,既然已经说到这了就介绍下浅复制和深复制的概念吧
浅复制:被复制对象的所有变量都含有与原来对象相同的值,而所有的对其他对象是引用都仍然指向原来的对象。
深复制:就是把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
深复制演示示例
修改工作经历实现克隆
package com.chenpt.designModel.prototypeModel;
/**
* @Author: chenpengtao
* @Description: 工作经历
* @Date: created in 2018/8/1
* @Modified By:
*/
public class WorkExperience implements Cloneable{
private String workDate;
private String company;
public WorkExperience(String workDate,String company){
this.workDate=workDate;
this.company=company;
}
public WorkExperience(){}
public String getWorkDate() {
return workDate;
}
public void setWorkDate(String workDate) {
this.workDate = workDate;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public Object clone(){
try {
return super.clone();
}catch (Exception e){
return null;
}
}
}
修改resume对象
package com.chenpt.designModel.prototypeModel;
import java.io.Serializable;
/**
* @Author: chenpengtao
* @Description: 简历
* @Date: created in 2018/8/1
* @Modified By:
*/
public class Resume implements Cloneable,Serializable{
private static final long serialVersionUID = 1L;
private String name;
private String sex;
private String age;
private WorkExperience workExperience;
Resume(String name,String sex,String age){
this.name=name;
this.sex=sex;
this.age=age;
this.workExperience=new WorkExperience();
}
/**
* 添加私有构造 克隆工作经历
* @param workExperience
*/
private Resume(WorkExperience workExperience){
this.workExperience= (WorkExperience) workExperience.clone();
}
/**
* 设置个人信息
* @param sex
* @param age
*/
public void setPersonInfo(String sex,String age){
this.sex=sex;
this.age=age;
}
/**
* 设置工作经历
* @param workDate
* @param company
*/
public void setWorkExperience(String workDate, String company){
this.workExperience.setWorkDate(workDate);
this.workExperience.setCompany(company);
}
//描述
public void dispaly(){
System.out.println("姓名:"+name+"\t年龄:"+age+"\t性别:"+sex);
System.out.println("工作经历:"+workExperience.getWorkDate()+"\t"+workExperience.getCompany());
}
/**
* 重写了克隆方法
* @return
*/
public Object clone(){
try {
Resume resume = new Resume(this.workExperience);//调用私有构造器实现工作经历克隆
//给对象属性重新赋值--最终返回的是深复制的resume对象
resume.name=this.name;
resume.sex=this.sex;
resume.age=this.age;
return resume;
}catch (Exception e){
return null;
}
}
}
客户端
package com.chenpt.designModel.prototypeModel;
/**
* @Author: chenpengtao
* @Description:
* @Date: created in 2018/8/1
* @Modified By:
*/
public class MainTest {
public static void main(String[] args){
Resume resume = new Resume("大鸟","男","25");
resume.setWorkExperience("2015-2016","南京工作");
Resume resume2 = (Resume)resume.clone();
resume2.setPersonInfo("男","26");
resume2.setWorkExperience("2016-2018","上海工作");
resume.dispaly();
resume2.dispaly();
}
}
//执行结果
姓名:大鸟 年龄:25 性别:男
工作经历:2015-2016 南京工作
姓名:大鸟 年龄:26 性别:男
工作经历:2016-2018 上海工作