简单的复制粘贴代码会对之后的程序维护形成巨大的工做量。java
为了不这种灾难的诞生,咱们今天来学习原型模式,仍是用代码来逐步过渡到原型模式(建立型模式)的讲解吧。spring
假设今天开学啦,有小明,小红,小猪入学报到!数据库
先来一个学生档案类,有院系,入学时间,毕业时间几个属性,和属性的set/get方法设计模式
1 public class StudentFiles { 2 private String department; 3 private String admissionTime; 4 private String graduationTime; 5 6 public StudentFiles(String department, String admissionTime, String graduationTime) { 7 this.department = department; 8 this.admissionTime = admissionTime; 9 this.graduationTime = graduationTime; 10 } 11 12 @Override 13 public String toString() { 14 return "StudentFiles{" + 15 "department='" + department + '\'' + 16 ", admissionTime='" + admissionTime + '\'' + 17 ", graduationTime='" + graduationTime + '\'' + 18 '}'; 19 } 20 }
再来一个学生类,有姓名,年龄和档案三个属性ide
1 public class Student { 2 private String name; 3 private int age; 4 private StudentFiles studentFiles; 5 6 public Student(String name, int age) { 7 this.name = name; 8 this.age = age; 9 } 10 11 public StudentFiles getStudentFiles() { 12 return studentFiles; 13 } 14 15 public void setStudentFiles(StudentFiles studentFiles) { 16 this.studentFiles = studentFiles; 17 } 18 19 @Override 20 public String toString() { 21 return "Student{" + 22 "name='" + name + '\'' + 23 ", age=" + age + 24 ", studentFiles=" + studentFiles + 25 '}'; 26 } 27 } 28 29 30 如今开始给他们办理入学手续 31 客户端代码 32 public class Client { 33 public static void main(String[] args) { 34 StudentFiles xiaohongFiles = new StudentFiles("计算机系","2019-5-8","2023-5-8"); 35 Student xiaohong=new Student("小红",22); 36 xiaohong.setStudentFiles(xiaohongFiles); 37 38 StudentFiles xiaomingFiles = new StudentFiles("计算机系","2019-5-8","2023-5-8"); 39 Student xiaoming=new Student("小明",21); 40 xiaoming.setStudentFiles(xiaomingFiles); 41 42 StudentFiles xiaozhuFiles = new StudentFiles("计算机系","2019-5-8","2023-5-8"); 43 Student xiaozhu=new Student("小猪",23); 44 xiaozhu.setStudentFiles(xiaozhuFiles); 45 46 System.out.println(xiaohong.toString()); 47 System.out.println(xiaoming.toString()); 48 System.out.println(xiaozhu.toString()); 49 } 50 }
结果学习
如今三位同窗开开心心的去上学了,可是咱们发现档案是个属性相同的对象。咱们在建立的时候只是简单的复制粘贴过来的,复制粘贴的代码越多维护代码也就越多 。this
那咱们只制做一份档案试试?spa
1 public class Client { 2 public static void main(String[] args) { 3 StudentFiles studentFiles = new StudentFiles("计算机系","2019-5-8","2023-5-8"); 4 5 Student xiaohong=new Student("小红",22); 6 xiaohong.setStudentFiles(studentFiles); 7 8 Student xiaoming=new Student("小明",21); 9 xiaoming.setStudentFiles(studentFiles); 10 11 Student xiaozhu=new Student("小猪",23); 12 xiaozhu.setStudentFiles(studentFiles); 13 14 System.out.println(xiaohong.toString()); 15 System.out.println(xiaoming.toString()); 16 System.out.println(xiaozhu.toString()); 17 } 18 }
结果设计
看了下结果是对的,但是别开心的太早。
如今小猪同窗表现一点都很差,不能再学校按时毕业了,要延期一年。code
1 studentFiles.setGraduationTime("2024-5-8");
结果
好了,如今小明和小红都要延期毕业了,是否是会气死其余两个同窗。
分析一下缘由:咱们只建立了一份档案,让三个同窗的档案都指向了这个档案了,三个档案是同一份档案,这固然不合乎常理了。每一个人的档案都应该属于本身,而不是和别人共用。
究其发生上面状况的缘由是由于咱们既不想复制代码,偷懒又出现了大问题。那么存在那种咱们经过代码来复制对象的可能的方法吗?
有的就是接下来出场的原型模式:
由于这个模式使用频繁,全部java已经给咱们封装好了,咱们只须要掌握使用便可。
首先让类实现Cloneable接口,接着重写clone方法
1 public Object clone() throws CloneNotSupportedException{ 2 return super.clone(); 3 }
此时的客户端代码
1 StudentFiles xiaohongStudentFiles= (StudentFiles) studentFiles.clone(); 2 StudentFiles xiaomingStudentFiles= (StudentFiles) studentFiles.clone(); 3 StudentFiles xiaozhuStudentFiles= (StudentFiles) studentFiles.clone();
那咱们再来看看这样复制真的能够吗,假设小猪不想和小红作同窗了,他要转到电信院去。
1 xiaozhuStudentFiles.setDepartment("电信院");
结果
既然咱们已经作好了偷懒的准备,为何不进行到底呢?
其实咱们已经了解到来上学的同窗大多都是22岁,只有极个别是其余年龄。
那咱们复制学生类好了,再给每一个学生都赋上他们的姓名便可。
1 public Object clone() throws CloneNotSupportedException{ 2 return super.clone(); 3 }
客户端的代码
public class Client { public static void main(String[] args) throws CloneNotSupportedException { StudentFiles studentFiles = new StudentFiles("计算机系","2019-5-8","2023-5-8"); Student student=new Student(22);//student的原型 student.setStudentFiles(studentFiles); Student xiaohong= (Student) student.clone(); xiaohong.setName("小红"); Student xiaoming=(Student) student.clone(); xiaoming.setName("小明"); xiaoming.setAge(15); Student xiaozhu=(Student) student.clone(); xiaozhu.setName("小猪"); System.out.println(xiaohong.toString()); System.out.println(xiaoming.toString()); System.out.println(xiaozhu.toString()); } }
咱们发现小明原来是个神通,才15岁是同窗中的特例,咱们为他修改下年龄。
结果
聪明的小明提早一年修满了全部学分,他要提早毕业了。
1 StudentFiles tmp = xiaoming.getStudentFiles(); 2 tmp.setGraduationTime("2022-5-8"); 3 xiaoming.setStudentFiles(tmp);
结果
能够看到同窗们都沾了小明的光提早毕业了,可是学校不容许这样的状况发生呀,咱们来研究下缘由吧:
咱们先了解浅拷贝和深拷贝的概念
浅拷贝:只拷贝基本数据类型,对于对象属性拷贝其中的引用地址
深拷贝:复制的时候基本数据类型和对象引用都拷贝一份
很显然咱们的拷贝是属于浅拷贝,咱们修改年龄对其余人没有影响,可是咱们修改学籍对象的时候,每一个拷贝的对象都发生了修改。
那java的深拷贝是怎么实现的呢?
咱们修改一下Student的clon方法便可
1 public Object clone() throws CloneNotSupportedException{ 2 Student student=(Student)super.clone(); 3 student.setStudentFiles((StudentFiles)studentFiles.clone()); 4 return student; 5 }
结果
总结:
浅拷贝:复制基本数据类型,引用类型没有进行复制
步骤:
1.实现Cloneable接口
2.实现clone方法
1 public Object clone() throws CloneNotSupportedException{ 2 return super.clone(); 3 }
深拷贝:复制基本数据类型和引用类型
步骤:
1.实现Cloneable接口
2.实现clone方法
1 public Object clone() throws CloneNotSupportedException{ 2 Student student=(Student)super.clone(); 3 student.setStudentFiles((StudentFiles)studentFiles.clone()); 4 return student; 5 }
原型模式优势:
1.抽象出共同点,仅须要修改对象间的不一样点
2.大大减小JVM建立对象的时间
实际上是有遇到过相似的状况的,只不过由于并无学习到这里,当时使用了最笨的办法一次次的new一个对象。
好比如今有一个student的list集合建立,而后批量插入数据库。在循环处的new对象彻底能够改为(Student) student.clone(),修改其中的属性便可。大大减小java徐理解建立对象的时间,同时代码也相对简洁。
到这里建立型模式(建造者模式,工厂模式,原型模式)都搞定了,还剩下单例模式还没写博客了。
单例模式十分重要,运用spring的bean的建立上,是spring IOC的重要设计模式。