原型模式

  • 原型模式
    • 背景
      • 克隆问题
    • 改进
    • 代码
      • 应用场景
    • 浅拷贝
    • 深拷贝
    • 注意事项与细节

原型模式

背景

克隆问题

类似过程:

//原始对象
User user=new User();
user.setName("...");
//...对象属性的操作;//如果需要克隆三个对象;
User user1=new User();
user1.setName(user.getName());
//...user1设置属性User user2=new User();
user2.setName(user.getName());
//...user2设置属性User user3=new User();
user3.setName(user.getName());
//...user设置属性

传统方式在创建新对象时,总是需要重新获取原始对象的属性,如果创建的对象比较复杂,开发效率会变低。而且,总是需要重新初始化对象,而不是动态的获取对象运行时的状态,不够灵活;

改进

思路:Java中Object类是所有类的根类,Object类提供了一个clone()方法,该方法可以将一个Java对象复制一份,但是需要实现clone的Java类必须要实现一个接口Cloneable。

该接口表示该类能够复制且具有复制的能力 => 原型模式

1)用原型实例指定厂家对象的种类、并且通过拷贝这些原型、创建新的对象;
2)原型模式是一种创建型设计模式、允许一个对象在创建一个可定制的对象、无需知道如何创建的细节;
3)工作原理:通过将一个原型对象传给哪个要发动创建的对象、这个要发动创建的对象通过请求原型拷贝他们自己来实施创建、 对象.clone();

  1. Prototype : 原型类,声明一个克隆自己的接口
  2. ConcretePrototype: 具体的原型类, 实现一个克隆自己的操作
  3. Client: 让一个原型对象克隆自己,从而创建一个新的对象(属性一样)

使用原型模式改进传统方式,让程序具有更高的效率和扩展性。

代码

package com.yxj.prototype.improve;public class Sheep implements Cloneable {private String name;private int age;private String color;private String address = "蒙古羊";public Sheep(String name, int age, String color) {super();this.name = name;this.age = age;this.color = color;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}@Overridepublic String toString() {return "Sheep [name=" + name + ", age=" + age + ", color=" + color + ", address=" + address + "]";}//克隆该实例,使用默认的clone方法来完成@Overrideprotected Object clone()  {Sheep sheep = null;try {sheep = (Sheep)super.clone();} catch (Exception e) {// TODO: handle exceptionSystem.out.println(e.getMessage());}// TODO Auto-generated method stubreturn sheep;}}package com.yxj.prototype.improve;public class Client {public static void main(String[] args) {System.out.println("原型模式完成对象的创建");// TODO Auto-generated method stubSheep sheep = new Sheep("tom", 1, "白色");Sheep sheep2 = (Sheep)sheep.clone(); //克隆Sheep sheep3 = (Sheep)sheep.clone(); //克隆Sheep sheep4 = (Sheep)sheep.clone(); //克隆Sheep sheep5 = (Sheep)sheep.clone(); //克隆System.out.println("sheep2 =" + sheep2);System.out.println("sheep3 =" + sheep3);System.out.println("sheep4 =" + sheep4);System.out.println("sheep5 =" + sheep5);}}

应用场景

在SpringIOC容器中,bean的类型有singleton,还有prototype;
前者是单例,后者是原型,每次从容器中获取的对象都是新的对象。


if (mbd.isSingleton()) {sharedInstance = this.getSingleton(beanName, () -> {try {return this.createBean(beanName, mbd, args);} catch (BeansException var5) {this.destroySingleton(beanName);throw var5;}});bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {var11 = null;Object prototypeInstance;try {this.beforePrototypeCreation(beanName);prototypeInstance = this.createBean(beanName, mbd, args);} finally {this.afterPrototypeCreation(beanName);}bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

浅拷贝

  1. 对于数据类型是基本数据类型的成员变量、浅拷贝会直接进行值传递、将值复制一份给新的对象;
  2. 如果是引用数据类型的成员变量、浅拷贝会进行引用传递、也就是将该成员变量的引用值(内存地址)复制一份给新的对象。实际上两个对象的该成员变量都指向同一个实例。
  3. 在这种情况下、在一个对象中修改该成员变量会影响另一个对象的成员变量值;
package com.yxj.prototype.improve;public class Sheep implements Cloneable {private String name;private int age;private String color;private String address = "蒙古羊";public Sheep friend; //是对象, 克隆是会如何处理public Sheep(String name, int age, String color) {super();this.name = name;this.age = age;this.color = color;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}@Overridepublic String toString() {return "Sheep [name=" + name + ", age=" + age + ", color=" + color + ", address=" + address + "]";}//克隆该实例,使用默认的clone方法来完成@Overrideprotected Object clone()  {Sheep sheep = null;try {sheep = (Sheep)super.clone();} catch (Exception e) {// TODO: handle exceptionSystem.out.println(e.getMessage());}// TODO Auto-generated method stubreturn sheep;}}package com.yxj.prototype.improve;public class Client {public static void main(String[] args) {System.out.println("原型模式完成对象的创建");// TODO Auto-generated method stubSheep sheep = new Sheep("tom", 1, "白色");sheep.friend = new Sheep("jack", 2, "黑色");Sheep sheep2 = (Sheep)sheep.clone(); //克隆Sheep sheep3 = (Sheep)sheep.clone(); //克隆Sheep sheep4 = (Sheep)sheep.clone(); //克隆Sheep sheep5 = (Sheep)sheep.clone(); //克隆System.out.println("sheep2 =" + sheep2 + "sheep2.friend=" + sheep2.friend.hashCode());System.out.println("sheep3 =" + sheep3 + "sheep3.friend=" + sheep3.friend.hashCode());System.out.println("sheep4 =" + sheep4 + "sheep4.friend=" + sheep4.friend.hashCode());System.out.println("sheep5 =" + sheep5 + "sheep5.friend=" + sheep5.friend.hashCode());}}

这是浅拷贝,属性friend引用都指向堆中的同一个对象;

深拷贝

1)复制对象的所有基本数据类型的成员变量值;
2)为所有引用数据类型的成员变量申请存储空间、并复制每个引用类型成员变量所引用的对象,直到该对象可达的所有对象;也就是、对象进行深拷贝就是对整个对象进行拷贝;
3)深拷贝实现方式:重写Clone方法来实现深拷贝;
4)深拷贝实现方式2:通过对象序列化实现深拷贝;

package com.yxj.prototype.deepclone;import java.io.Serializable;public class DeepCloneableTarget implements Serializable, Cloneable {/*** */private static final long serialVersionUID = 1L;private String cloneName;private String cloneClass;//构造器public DeepCloneableTarget(String cloneName, String cloneClass) {this.cloneName = cloneName;this.cloneClass = cloneClass;}//因为该类的属性,都是String , 因此我们这里使用默认的clone完成即可@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}package com.yxj.prototype.deepclone;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;public class DeepProtoType implements Serializable, Cloneable{public String name; //String 属性public DeepCloneableTarget deepCloneableTarget;// 引用类型public DeepProtoType() {super();}//深拷贝 - 方式 1 使用clone 方法@Overrideprotected Object clone() throws CloneNotSupportedException {Object deep = null;//这里完成对基本数据类型(属性)和String的克隆deep = super.clone(); //对引用类型的属性,进行单独处理DeepProtoType deepProtoType = (DeepProtoType)deep;deepProtoType.deepCloneableTarget  = (DeepCloneableTarget)deepCloneableTarget.clone();// TODO Auto-generated method stubreturn deepProtoType;}//深拷贝 - 方式2 通过对象的序列化实现 (推荐)public Object deepClone() {//创建流对象ByteArrayOutputStream bos = null;ObjectOutputStream oos = null;ByteArrayInputStream bis = null;ObjectInputStream ois = null;try {//序列化bos = new ByteArrayOutputStream();oos = new ObjectOutputStream(bos);oos.writeObject(this); //当前这个对象以对象流的方式输出//反序列化bis = new ByteArrayInputStream(bos.toByteArray());ois = new ObjectInputStream(bis);DeepProtoType copyObj = (DeepProtoType)ois.readObject();return copyObj;} catch (Exception e) {// TODO: handle exceptione.printStackTrace();return null;} finally {//关闭流try {bos.close();oos.close();bis.close();ois.close();} catch (Exception e2) {// TODO: handle exceptionSystem.out.println(e2.getMessage());}}}}package com.yxj.prototype.deepclone;public class Client {public static void main(String[] args) throws Exception {// TODO Auto-generated method stubDeepProtoType p = new DeepProtoType();p.name = "宋江";p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛");//方式1 完成深拷贝//       DeepProtoType p2 = (DeepProtoType) p.clone();
//
//      System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
//      System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());//方式2 完成深拷贝DeepProtoType p2 = (DeepProtoType) p.deepClone();System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());}}

注意事项与细节

  1. 创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率
  2. 不用重新初始化对象,而是动态地获得对象运行时的状态
  3. 如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码
  4. 在实现深克隆的时候可能需要比较复杂的代码
  5. 缺点:需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了ocp原则,这点请同学们注意

设计模式之原型模式与深浅拷贝相关推荐

  1. 设计模式之原型模式以及深浅拷贝的区别

    原型模式也是创建对象的一种方式,它一般用在这样的场景:系统中存在大量相同或相似对象的创建问题,如果用传统的构造函数来创建对象,会比较复杂而且耗费资源.这个时候使用原型模式的克隆方式,能够节省不少时间. ...

  2. 设计模式学习笔记(六)原型模式以及深浅拷贝的区别

    原型模式也是创建对象的一种方式,它一般用在这样的场景:系统中存在大量相同或相似对象的创建问题,如果用传统的构造函数来创建对象,会比较复杂而且耗费资源.这个时候使用原型模式的克隆方式,能够节省不少时间. ...

  3. 设计模式_4_原型模式(对象的拷贝)

    原形模式(PrototypePattern, 创建型模式,创建重复对象且保证性能, 对象的克隆) 通常使用原型模式创建一个原型接口, 用于获取创建对象的克隆, 对于浅拷贝与深拷贝不用纠结, 他们二者的 ...

  4. 原型模式 java 深浅_java学习笔记之原型模式及深浅拷贝

    一.原型模式的基本介绍 在聊原型模式之前,我们来思考一个小问题,传统的方式我们是如何克隆对象呢? 那我们以多利羊(Sheep)为例,来说明上述这个问题,具体代码见下面: 多利羊(Sheep) publ ...

  5. Head First设计模式之原型模式

    一.定义 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 原型模式是一种比较简单的模式,也非常容易理解,实现一个接口,重写一个方法即完成了原型模式.在实际应用中,原型模式很少单独出现 ...

  6. java 肌汉模式_设计模式之原型模式详解(附源代码)

    原型模式(Prototype Pattern) 原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. ...

  7. 乐在其中设计模式(C#) - 原型模式(Prototype Pattern)

    [索引页] [源码下载] 乐在其中设计模式(C#) - 原型模式(Prototype Pattern) 作者:webabcd 介绍 用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象. ...

  8. 教你如何一篇博客读懂设计模式之—--原型模式

    教你如何一篇博客读懂设计模式之----原型模式 what:是什么 原型模式: 用于创建重复的对象,既不用一个属性一个属性去set和get,又不影响性能,原型模式产生的对象和原有的对象不是同一个实例,他 ...

  9. C#设计模式(6)——原型模式(Prototype Pattern)

    一.引言 在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创建这样的类实例,这未免会增加创建类的复杂度和耗费更多的内存空间,因为这样在 ...

最新文章

  1. 如何绕过chrome的弹窗拦截机制
  2. HihoCode1721删除一个字符之后是回文字符串
  3. UVa OJ 120
  4. ActiveMQ点对点消息通信demo
  5. 不常见但是有用的 Chrome 调试技巧
  6. MySQL的CSV引擎应用实例解析
  7. com.android.pngp.tln,Android资源之图像资源(图像级别资源)
  8. R语言·文本挖掘︱Rwordseg/rJava两包的安装(安到吐血)
  9. hive表中加载数据
  10. TCP/IP协议新手入门学习
  11. hadoop常用端口号
  12. html5橡皮擦,用HTML5 Canvas API中的clearRect()方法实现橡皮擦功能
  13. 一个美式英语发音的app开源
  14. 【Qt设计开发】GUI界面设计开发
  15. WannaCry爆发一年后,EternalBlue的威胁仍然存在
  16. 【读书】2020年阅读记录及心得
  17. 手把手带你开发一个批量下载资源的谷歌浏览器扩展
  18. Xcode各版本和IOS模拟器个版本下载
  19. 亚马逊测评自养号环境系统的介绍和用法
  20. 关于腾讯TBS中,加载失败问题(64位手机无法加载x5)

热门文章

  1. 关于死锁,死锁的四个必要条件的总结
  2. 什么是QQ卡片制作?
  3. 我的专业我做主计算机演讲稿,我的未来我做主演讲稿作文
  4. IT忍者神龟之理解回顾面向对象的 JavaScript
  5. 计算机网络实验(4)--配置网络路由
  6. php 将数组结果作为返回值保存到php文件中
  7. basemap基础投影与地图样式
  8. idea快捷键打开run的窗口_看了上篇文章,你不了解的IDEA操作……
  9. Acwing 1126. 最小花费【图论、单源最短路】
  10. Java语言基础(环境搭建、语法、变量、类型转换、运算符、控制语句、数组)