原型模式(Prototype )

简单的复制粘贴代码会对之后的程序维护形成巨大的工做量。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的重要设计模式。