写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用,主要是下面的UML图可以起到大作用,在你学习过一遍以后可能会遗忘,忘记了不要紧,只要看一眼UML图就能想起来了。同时也请大家多多指教。
原型模式(Prototype)
目录
一、概述
1、用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象;2、可以从一个对象再创建另外一个可定制的对象,而且不需要知道任何的细节;3、不用重新初始化对象,而是动态地获得对象运行时得状态。
1.1、主要的角色就一种:
- 待克隆的对象:也就是需要频繁被复制的对象,我们采用克隆的思想去复制他。
或许会有疑问,这个模式不就是复制实例对象吗?着我手动代码就复制了,有必要专门讨论吗?和一般一行一行代码复制不一样,这个的理论是希望他能直接在内存里就复制过去,而不是我们再创建一片空间,然后把对象属性一个一个复制过去。就此我们将对比两种方式、如下图
1.2、 一般复制和原型模式的对比:
1.3、通过技术实现的角度看,UML图如下:
二、优点
提高了性能、也减少了重复代码
三、使用步骤
- 如果有某个类需要同时创建大量的实例,并且这个类的实例大都相似,那么就可以考虑使用原型模式;
- 实现原型模式对于不同语言有不同的方式,但应该提供一个接口,用来克隆对象实例。
四、举例(深复制)
假设张三要写两份简历,简历里有姓名、性别、年龄、以及工作经历,其中工作经历是一个引用对象;因为某些原因,两份简历,其中年龄不一样(一个是25岁,一个是28岁)、工作经历不一样(一个是在度百工作经历,一个是讯腾工作经历),其他的都一样。
4.1、分析步骤:
1、分析上述问题:
- 我们发现完全填写好一份简历比较麻烦,且此简历都属于同一个人,只是某些项有不同,此时我们可以考虑原型模式;
- 对于原型模式,实际实现时都是去实现克隆接口,此接口应当可以完成对实例的完整复制;
- 另外本例有一个引用对象——工作经历,一般情况下复制是简历里变量的值,也就是工作经历引用地址,所以会导致多个简历实例对象里的工作经历变量指向同一个工作经历实例对象,这肯定是有问题的,还需要另外的处理,就是让工作经历类也可以克隆,也即深复制。这样每次克隆或复制简历对象时,也克隆工作经历,让新复制的简历里的工作经历变量也指向新复制的实例。同理,当有多个引用对象时,应当都应用原型模式,使其可以克隆或复制。
2、针对问题的设计要素:
- 简历类
- 工作经历类
都要实现克隆或复制。
4.2、uml图如下:
4.3、Java实现代码如下(建议你在本地试一下,加深印象):
(对于Java实现原型模式,需要实现Cloneable接口,然后再写clone方法)
工作经历类:
public class WorkExperience implements Cloneable {
private String timeArea; //工作时间
public String getTimeArea() {
return timeArea;
}
public void setTimeArea(String timeArea) {
this.timeArea = timeArea;
}
private String company; //工作公司名称
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public WorkExperience clone() { //实现克隆接口
WorkExperience workExperience = null;
try {
workExperience = (WorkExperience) super.clone();
} catch (CloneNotSupportedException e) {
System.out.println("Clone异常");
}
return workExperience;
}
}
简历类:
public class Resume implements Cloneable{
private String name; //姓名
private String sex; //性别
private String age; //年龄
private WorkExperience workExperience; //工作经历类
public Resume(String name) {
this.name = name;
this.workExperience = new WorkExperience();
}
public void setPersonalInfo(String sex, String age) {
this.sex = sex;
this.age = age;
}
public void setWorkExperience(String timeArea, String company) {
this.workExperience.setTimeArea(timeArea);
this.workExperience.setCompany(company);
}
public void display() { //展示简历
System.out.println(this.name + " " + this.sex + " " + this.age);
System.out.println("工作经历:" + this.workExperience.getTimeArea() + " " + this.workExperience.getCompany());
}
public Resume clone(){ //实现克隆接口
Resume resume = null;
try {
resume = (Resume) super.clone();
resume.workExperience = this.workExperience.clone(); //调用对引用对象工作经历的克隆接口,将新复制的工作经历实例对象复制给本对象的成员变量,从而最终能够实现深复制
} catch (CloneNotSupportedException e) {
System.out.println("Clone异常");
}
return resume;
}
}
主程序(发起请求的类):
public class Main {
public static void main(String[] args) {
//第一份简历
Resume resume1 = new Resume("张三");
resume1.setPersonalInfo("man", "25");
resume1.setWorkExperience("2015-2018", "度百");
//第二份简历
Resume resume2 = resume1.clone(); //复制第一份简历,然后再第一份简历上做简单修改可以得到第二份简历
resume2.setPersonalInfo("man", "28");
resume2.setWorkExperience("2018-2021", "讯腾");
System.out.println("第一份简历:");
resume1.display(); //展示简历1
System.out.println("第二份简历:");
resume2.display(); //展示简历2
}
}
这里就不再举例了,可以把上面的Java例子复制到你本地,运行main函数试一下加深理解。这些代码都是我自己学习的时候根据一些教材手敲的,不存在bug可以直接运行。
如果觉得本文还不错,就请点个赞吧!如果有建议,也请评论指教和讨论!