博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
原型模式(Prototype )
阅读量:5789 次
发布时间:2019-06-18

本文共 6111 字,大约阅读时间需要 20 分钟。

简单的复制粘贴代码会对以后的程序维护造成巨大的工作量。

为了避免这种灾难的诞生,我们今天来学习原型模式,还是用代码来逐步过渡到原型模式(创建型模式)的讲解吧。

 

假设今天开学啦,有小明,小红,小猪入学报到!

先来一个学生档案类,有院系,入学时间,毕业时间几个属性,和属性的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     @Override13     public String toString() {14         return "StudentFiles{" +15                 "department='" + department + '\'' +16                 ", admissionTime='" + admissionTime + '\'' +17                 ", graduationTime='" + graduationTime + '\'' +18                 '}';19     }20 }

再来一个学生类,有姓名,年龄和档案三个属性

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     @Override20     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 }

结果

现在三位同学开开心心的去上学了,但是我们发现档案是个属性相同的对象。我们在创建的时候只是简单的复制粘贴过来的,复制粘贴的代码越多维护代码也就越多 。

 

那我们只制作一份档案试试?

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 }

结果

看了下结果是对的,可是别开心的太早。

现在小猪同学表现一点都不好,不能再学校按时毕业了,要延期一年。

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的重要设计模式。

转载于:https://www.cnblogs.com/Gang-Bryant/p/10834475.html

你可能感兴趣的文章
深入.net框架
查看>>
聚合类新闻client产品功能点详情分析
查看>>
js设置定时器
查看>>
数据库除运算
查看>>
LeetCode--112--路径总和
查看>>
DeviceIOControl与驱动层 - 缓冲区模式
查看>>
感悟贴2016-05-13
查看>>
vim使用教程
查看>>
JDK在LINUX系统平台下的部署案例与总结
查看>>
跨vlan通信-----单臂路由技术
查看>>
百度编辑器ueditor 光标位置的坐标
查看>>
DEV-C++ 调试方法简明图文教程(转)
查看>>
VS2017+EF+Mysql生成实体数据模型(解决闪退的坑)
查看>>
C++多态、继承的简单分析
查看>>
库克称未来苹果用户可自己决定是否降频 网友:你是在搞笑吗?
查看>>
6倍性能差100TB容量,阿里云POLARDB咋实现?
查看>>
linux 安装 MySQLdb for python
查看>>
Sublime Text 2 技巧
查看>>
使用fscanf()函数从磁盘文件读取格式化数据
查看>>
参加婚礼
查看>>