ITPub博客

首页 > > > 23种设计模式之——原型模式

23种设计模式之——原型模式

作者:孤独键客 时间:2020-05-13 11:04:54 0 删除 编辑


点击上方“程序员的成长之路”,选择“置顶公众号”

技术文章第一时间送达!


什么是原型模式?


用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

原型模式其实就是一个对象在创建另一个可定制的对象,而且不需要指定任何创建的细节。Java提供了Coneable接口,其中有一个唯一方法Clone(),实现这个接口就可以完成原型模式了。


什么时候使用它呢?


一般在初始化的信息不发生变化的情况下,克隆是最好的办法。既隐藏了对象创建的细节,又对性能是大大的提高。不用重新初始化对象,而是动态地获得对象运行时的状态。

 

面试的时候需要递交简历,很多家公司需要去面试,一份简历就需要复印很多份,下面通过简历的事件来模拟原型模式。


原型模式实现:

简历类

  1. /**

  2. * 作者:LKP

  3. * 时间:2018/7/27

  4. * 简历类

  5. */

  6. public class Resume implements Cloneable {

  7. private String name;

  8. private String sex;

  9. private String age;

  10. private String timeArea;

  11. private String company;

  12. public Resume(String name){

  13. this.name = name;

  14. }

  15. //设置个人信息

  16. public void SetPersonalInfo(String sex,String age){

  17. this.sex = sex;

  18. this.age = age;

  19. }

  20. //设置工作经历

  21. public void SetWorkExperience(String timeArea,String company){

  22. this.timeArea = timeArea;

  23. this.company = company;

  24. }

  25. //显示

  26. public void Display(){

  27. System.out.println(name+"\t"+sex+"\t"+age);

  28. System.out.println("工作经历:"+timeArea+"\t"+company);

  29. }

  30. @Override

  31. protected Object clone() throws CloneNotSupportedException {

  32. return super.clone();

  33. }

  34. }

客户端实现:

  1. /**

  2. * 作者:LKP

  3. * 时间:2018/7/27

  4. * 客户端

  5. */

  6. public class Client {

  7. public static void main(String[] args) throws CloneNotSupportedException {

  8. Resume a = new Resume("小明");

  9. a.SetPersonalInfo("男","29");

  10. a.SetWorkExperience("1998-2000","xx公司");

  11. Resume b = (Resume) a.clone();

  12. b.SetWorkExperience("1998-2018","YY公司");

  13. Resume c = (Resume) a.clone();

  14. c.SetPersonalInfo("男","24");

  15. a.Display();

  16. b.Display();

  17. c.Display();

  18. }

  19. }

运行结果

只需要调用Clone方法就可以实现新简历的生成,并且可以再修改新简历的细节。

它的好处,不用重新初始化对象,而是动态地获得对象运行时的状态。

 

原型模式有两种情况:

一种是浅复制,一种是深复制。

 

Clone()方法是这样的,如果字段是值类型的,则对该字段执行逐位复制,如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。

接下来我们来看看这一现象:

新增工作经历类:

  1. /**

  2. * 作者:LKP

  3. * 时间:2018/7/27

  4. * 工作经历类

  5. */

  6. public class WorkExperience {

  7. private String workDate;

  8. private String company;

  9. public String getWorkDate() {

  10. return workDate;

  11. }

  12. public void setWorkDate(String workDate) {

  13. this.workDate = workDate;

  14. }

  15. public String getCompany() {

  16. return company;

  17. }

  18. public void setCompany(String company) {

  19. this.company = company;

  20. }

  21. }

修改简历类:

引用“工作经历”对象;在“简历”类实例化时同时实例化“工作经历”。

  1. /**

  2. * 作者:LKP

  3. * 时间:2018/7/27

  4. * 简历类

  5. */

  6. public class Resume implements Cloneable {

  7. private String name;

  8. private String sex;

  9. private String age;

  10. private WorkExperience work;

  11. public Resume(String name){

  12. this.name = name;

  13. work = new WorkExperience();

  14. }

  15. //设置个人信息

  16. public void SetPersonalInfo(String sex,String age){

  17. this.sex = sex;

  18. this.age = age;

  19. }

  20. //设置工作经历

  21. public void SetWorkExperience(String workDate,String company){

  22. work.setWorkDate(workDate);

  23. work.setCompany(company);

  24. }

  25. //显示

  26. public void Display(){

  27. System.out.println(name+"\t"+sex+"\t"+age);

  28. System.out.println("工作经历:"+work.getWorkDate()+"\t"+work.getCompany());

  29. }

  30. @Override

  31. protected Object clone() throws CloneNotSupportedException {

  32. return super.clone();

  33. }

  34. }

客户端代码进行细微修改:

  1. /**

  2. * 作者:LKP

  3. * 时间:2018/7/27

  4. * 客户端

  5. */

  6. public class Client {

  7. public static void main(String[] args) throws CloneNotSupportedException {

  8. Resume a = new Resume("小明");

  9. a.SetPersonalInfo("男","29");

  10. a.SetWorkExperience("1998-2000","xx公司");

  11. Resume b = (Resume) a.clone();

  12. b.SetWorkExperience("1998-2018","YY公司");

  13. Resume c = (Resume) a.clone();

  14. a.SetWorkExperience("1998-2000","ZZ公司");

  15. a.Display();

  16. b.Display();

  17. c.Display();

  18. }

  19. }

b和c都克隆于a,但当它们都设置了“工作经历”时,我们希望的结果是三个的显示不一样。

运行结果:

可惜,没有达到我们的要求,三次显示的结果都是最后一次设置的值。

 

这种原因,就叫做”浅复制“,被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。

我们可能更需要这样一个需求:把要复制的对象所引用的对象都复制一遍。

比如刚刚的例子,我们希望是a、b、c三个引用的对象都是不同的,复制时就一变二,二变三。这种复制的方式叫做“深复制”,深复制把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。

 

深复制代码实现:

修改我们刚刚创建的工作经历类,让其实现Coneable。“工作经历”类实现克隆方法。

  1. /**

  2. * 作者:LKP

  3. * 时间:2018/7/27

  4. * 工作经历类

  5. */

  6. public class WorkExperience implements Cloneable{

  7. private String workDate;

  8. private String company;

  9. public String getWorkDate() {

  10. return workDate;

  11. }

  12. public void setWorkDate(String workDate) {

  13. this.workDate = workDate;

  14. }

  15. public String getCompany() {

  16. return company;

  17. }

  18. public void setCompany(String company) {

  19. this.company = company;

  20. }

  21. @Override

  22. protected Object clone() throws CloneNotSupportedException {

  23. return super.clone();

  24. }

  25. }

简历类修改如下:

  1. /**

  2. * 作者:LKP

  3. * 时间:2018/7/27

  4. * 简历类

  5. */

  6. public class Resume implements Cloneable {

  7. private String name;

  8. private String sex;

  9. private String age;

  10. private WorkExperience work;

  11. public Resume(String name){

  12. this.name = name;

  13. work = new WorkExperience();

  14. }

  15. private Resume(WorkExperience work) throws CloneNotSupportedException {

  16. this.work = (WorkExperience) work.clone();

  17. }

  18. //设置个人信息

  19. public void SetPersonalInfo(String sex,String age){

  20. this.sex = sex;

  21. this.age = age;

  22. }

  23. //设置工作经历

  24. public void SetWorkExperience(String workDate,String company){

  25. work.setWorkDate(workDate);

  26. work.setCompany(company);

  27. }

  28. //显示

  29. public void Display(){

  30. System.out.println(name+"\t"+sex+"\t"+age);

  31. System.out.println("工作经历:"+work.getWorkDate()+"\t"+work.getCompany());

  32. }

  33. @Override

  34. protected Object clone() throws CloneNotSupportedException {

  35. Resume obj = new Resume(this.work);

  36. obj.name = this.name;

  37. obj.sex = this.sex;

  38. obj.age = this.age;

  39. return obj;

  40. }

  41. }

提供Clone方法调用私有构造函数,以便克隆“工作经历”的数据。

在clone方法调用私有的够着方法,让“工作经历”克隆完成,然后再给这个“简历”对象的相关字段赋值,最终返回一个深复制的简历对象。

客户端代码不变,运行结果显示:

达到了我们希望三次显示结果各不相同的需求。



END


扫一扫

关注我们



来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69902700/viewspace-3127451/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
一个不羁的码农,终身学习者。公众号「程序员的成长之路」。目前就职于一家游戏公司,主要负责服务器端,以及web系统的开发工作,对Java相关知识比较擅长。

注册时间:2018-12-14

  • 博文量
    793
  • 访问量
    119798