原型模式的应用场景
- 概念
原型模式指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。 - 核心
它是直接基于内存二进制流进行拷贝,无需再经历耗时的对象初始化过程(不调用构造函数),性能提升许多。 - 应用场景
当对象的构建过程比较耗时时,可以利用当前系统中已存在的对象作为原型,对其进行拷贝,躲避初始化过程,使得新对象的创建时间大大减少
一个恶心的小案例感受一下什么时候需要用到原型模式
@Data
public class ExamPaper{
private String examinationPaperId;//试卷主键
private String leavTime;//剩余时间
private String organizationId;//单位主键
private String id;//考试主键
private String examRoomId;//考场主键
private String userId;//用户主键
private String specialtyCode;//专业代码
private String postionCode;//报考岗位
private String gradeCode;//报考等级
private String examStartTime;//考试开始时间
private String examEndTime;//考试结束时间
private String singleSelectionImpCount;//单选选题重要数量
private String multiSelectionImpCount;//多选题重要数量
private String judgementImpCount;//判断题重要数量
private String examTime;//考试时长
private String fullScore;//总分
private String passScore;//及格分
private String userName;//学员姓名
private String score;//考试得分
private String resut;//是否及格
private String singleOkCount;//单选题答对数量
private String multiOkCount;//多选题答对数量
private String judgementOkCount;//判断题答对数量
public ExamPaper copy(){
ExamPaper examPaper = new ExamPaper();
//剩余时间
examPaper.setLeavTime(this.getLeavTime());
//单位主键
examPaper.setOrganizationId(this.getOrganizationId());
//考试主键
examPaper.setId(this.getId());
//用户主键
examPaper.setUserId(this.getUserId());
//专业
examPaper.setSpecialtyCode(this.getSpecialtyCode());
//岗位
examPaper.setPostionCode(this.getPostionCode());
//等级
examPaper.setGradeCode(this.getGradeCode());
//考试开始时间
examPaper.setExamStartTime(this.getExamStartTime());
//考试结束时间
examPaper.setExamEndTime(this.getExamEndTime());
//单选题重要数量
examPaper.setSingleSelectionImpCount(this.getSingleSelectionImpCount());
//多选题重要数量
examPaper.setMultiSelectionImpCount(this.getMultiSelectionImpCount());
//判断题重要数量
examPaper.setJudgementImpCount(this.getJudgementImpCount());
//考试时间
examPaper.setExamTime(this.getExamTime());
//总分
examPaper.setFullScore(this.getFullScore());
//及格分
examPaper.setPassScore(this.getPassScore());
//学员姓名
examPaper.setUserName(this.getUserName());
//分数
examPaper.setScore(this.getScore());
//单选答对数量
examPaper.setSingleOkCount(this.getSingleOkCount());
//多选答对数量
examPaper.setMultiOkCount(this.getMultiOkCount());
//判断答对数量
examPaper.setJudgementOkCount(this.getJudgementOkCount());
return examPaper;
}
}
太多set了,特别麻烦,使用BeanUtils改进后
public class BeanUtils {
public static Object copy(Object protorype) {
Class clazz = protorype.getClass();
Object returnValue = null;
try {
returnValue = clazz.newInstance();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
field.set(returnValue, field.get(protorype));
}
}catch (Exception e){
e.printStackTrace();
}
return returnValue;
}
}
注意:这里的BeanUtils并没有用到原型模式,因为它还是再用反射new对象,反射依然会调用构造器,它只是让代码更简单了
原型模式常用的写法
浅克隆
直接上代码
@Data
public class ConcretePrototype implements Cloneable {
private int age;
private String name;
private List<String> hobbies;
@Override
public ConcretePrototype clone() {
try {
return (ConcretePrototype)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
@Override
public String toString() {
return "ConcretePrototype{" +
"age=" + age +
", name='" + name + '\'' +
", hobbies=" + hobbies +
'}';
}
}
public class Client {
public static void main(String[] args) {
//创建原型对象
ConcretePrototype prototype = new ConcretePrototype();
prototype.setAge(18);
prototype.setName("Tom");
List<String> hobbies = new ArrayList<String>();
hobbies.add("书法");
hobbies.add("美术");
prototype.setHobbies(hobbies);
//拷贝原型对象
ConcretePrototype cloneType = prototype.clone();
cloneType.getHobbies().add("技术控");
System.out.println("原型对象:" + prototype);
System.out.println("克隆对象:" + cloneType);
System.out.println(prototype == cloneType);
System.out.println("原型对象的爱好:" + prototype.getHobbies());
System.out.println("克隆对象的爱好:" + cloneType.getHobbies());
System.out.println(prototype.getHobbies() == cloneType.getHobbies());
}
}
结果
我们可以看到hobbies这个链表只复制了引用地址,没有直接新建一份链表,这就是浅克隆
深克隆
@Data
public class ConcretePrototype implements Cloneable,Serializable {
private int age;
private String name;
private List<String> hobbies;
@Override
public ConcretePrototype clone() {
try {
return (ConcretePrototype)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
public ConcretePrototype deepCloneHobbies(){
try {
ConcretePrototype result = (ConcretePrototype)super.clone();
result.hobbies = (List)((ArrayList)result.hobbies).clone();
return result;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
public ConcretePrototype deepClone(){
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (ConcretePrototype)ois.readObject();
}catch (Exception e){
e.printStackTrace();
return null;
}
}
@Override
public String toString() {
return "ConcretePrototype{" +
"age=" + age +
", name='" + name + '\'' +
", hobbies=" + hobbies +
'}';
}
}
public class Client {
public static void main(String[] args) {
//创建原型对象
ConcretePrototype prototype = new ConcretePrototype();
prototype.setAge(18);
prototype.setName("Tom");
List<String> hobbies = new ArrayList<String>();
hobbies.add("书法");
hobbies.add("美术");
prototype.setHobbies(hobbies);
//拷贝原型对象
ConcretePrototype cloneType = prototype.deepCloneHobbies();
cloneType.getHobbies().add("技术控");
System.out.println("原型对象:" + prototype);
System.out.println("克隆对象:" + cloneType);
System.out.println(prototype == cloneType);
System.out.println("原型对象的爱好:" + prototype.getHobbies());
System.out.println("克隆对象的爱好:" + cloneType.getHobbies());
System.out.println(prototype.getHobbies() == cloneType.getHobbies());
}
}
结果
Spring中的Scope=“prototype”
这个意思就是它不是new对象(通过反射),而是根据内存中存在的已有的对象直接克隆