一、原型模式
原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象,属于创建型模式。
原型模式的核心在于拷贝原型对象。以系统中已存在的一个对象为原型,直接基于内存二进制流进行拷贝,无需再经历耗时的对象初始化过程(不调用构造函数),性能提升许多。当兑现的构建过程比较耗时时,可以利用当前系统中已存在的对象作为原型,对其进行克隆(一般是基于二进制流的复制),躲避初始化过程,使得新对象的创建时间大大减少。下面,我们来看看原型模式类结构图。
从UML图中,我们可以看到,原型模式,主要包含三个角色:
客户(Client):客户类提出创建对象的请求。
抽象原型(Prototype):规定拷贝接口。
具体原型(Concrete Prototype):被拷贝的对象。
注:对不通过new关键字,而是通过对象拷贝来实现创建对象的模式就称作原型模式。
原型模式的应用场景
你一定遇到过大篇幅getter、setter赋值的场景。例如这样的代码:
@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; } @Override public String toString() { return "ExamPaper{" + "examinationPaperId='" + examinationPaperId + '\'' + ", leavTime='" + leavTime + '\'' + ", organizationId='" + organizationId + '\'' + ", id='" + id + '\'' + ", examRoomId='" + examRoomId + '\'' + ", userId='" + userId + '\'' + ", specialtyCode='" + specialtyCode + '\'' + ", postionCode='" + postionCode + '\'' + ", gradeCode='" + gradeCode + '\'' + ", examStartTime='" + examStartTime + '\'' + ", examEndTime='" + examEndTime + '\'' + ", singleSelectionImpCount='" + singleSelectionImpCount + '\'' + ", multiSelectionImpCount='" + multiSelectionImpCount + '\'' + ", judgementImpCount='" + judgementImpCount + '\'' + ", examTime='" + examTime + '\'' + ", fullScore='" + fullScore + '\'' + ", passScore='" + passScore + '\'' + ", userName='" + userName + '\'' + ", score='" + score + '\'' + ", resut='" + resut + '\'' + ", singleOkCount='" + singleOkCount + '\'' + ", multiOkCount='" + multiOkCount + '\'' + ", judgementOkCount='" + judgementOkCount + '\'' + '}'; } }
代码非常工整,命名非常规范,注释也写的很全面,其实这就是原型模式的需求场景。但是,上述代码属于纯体力劳动。那原型模式,能帮助我们解决这样的问题。
原型模式主要适用于以下场景:
1、类初始化消化资源较多
2、new 产生的一个对象需要非常繁琐的过程(数据准备,访问权限等)
3、构造函数比较复杂
4、循环体中生产大量的对象时。
在Spring中,原型模式应用得非常广泛。例如 scope = “prototype”,在我们经常用的JSON。parseObject()也是一种原型模式。
原型模式的通用写法
一个标准的原型模式代码,应该是这样设计的,先创建原型IPrototype接口:
public interface IPrototype<T> { T clone(); }
创建具体需要克隆的对象ConcretePrototype
public class ConcretePrototype implements IPrototype { private int age; private String name; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public ConcretePrototype clone() { ConcretePrototype concretePrototype = new ConcretePrototype(); concretePrototype.setAge(this.age); concretePrototype.setName(this.name); return concretePrototype; } @Override public String toString() { return "ConcretePrototype{" + "age=" + age + ", name='" + name + '\'' + '}'; } }