原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

原型模式利用的是克隆的原理,创建新的对象,JDK提供的Cloneable 和JSON、springUtil里面的克隆都是一般浅克隆,与之对应的还有深克隆

1、浅克隆

  浅克隆也是穿件一个新的对象,不过该对象的属性值是被克隆对象的,如果修改被克隆对象,后者跟着修改。

下面我们用Cloneable写一个简单的浅克隆

import java.util.List;
/**
* @Description TODO
* @Author Bert
* @Date 2019\6\10 0010
*/
public class ShallowClone implements Cloneable{ private String name;
private int age;
private List<String> hobbies; 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 List<String> getHobbies() {
return hobbies;
} public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
} //实现 Cloneable 的 clone 方法 属于浅克隆
@Override
public ShallowClone clone() {
ShallowClone shallowClone = null;
try {
shallowClone = (ShallowClone)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return shallowClone;
} //手写 浅克隆 方法
public ShallowClone spellClone(){
ShallowClone shallowClone = new ShallowClone();
shallowClone.setName(this.name);
shallowClone.setAge(this.age);
shallowClone.setHobbies(this.hobbies);
return shallowClone;
}
}

  测试代码:

public static void main(String[] args) {

        ShallowClone shallowClone = new ShallowClone();
shallowClone.setName("ZhangSan");
shallowClone.setAge(21);
List<String> list = new ArrayList<>();
list.add("play game");
list.add("Listen music");
shallowClone.setHobbies(list); //调用Cloneable 的clone方法
ShallowClone clone1 = shallowClone.clone();
//添加喜好
shallowClone.getHobbies().add("fitness");
//调用手写的浅克隆方法
ShallowClone clone2 = shallowClone.spellClone(); System.out.println(shallowClone == clone1);//判读是否为同一个对象
System.out.println(shallowClone == clone2);//判读是否为同一个对象 System.out.println("克隆对象中引用类型地址:"+shallowClone.getHobbies());
System.out.println("克隆对象中引用类型地址:"+clone1.getHobbies());
System.out.println("克隆对象中引用类型地址:"+clone2.getHobbies());
}

  运行结果:

false
false
克隆对象中引用类型地址:[play game, Listen music, fitness]
克隆对象中引用类型地址:[play game, Listen music, fitness]
克隆对象中引用类型地址:[play game, Listen music, fitness]

  从运行结果我们可以看出,克隆对象和原来的对象不是同一个,但对象的属性完全一样,即使改变了其中一个,其他的也会跟着改变。

  通过上面spellClone() 方法我们可以看出,浅克隆的整个过程就是,创建一个新的对象,然后新对象的每个值都是由原对象的值,通过 = 进行赋值;

    (1)拷贝后获取的是一个独立的对象,和原对象拥有不同的内存地址;

    (2)基本元素类型,两者是隔离的,int, Integer, long, Long, char, Charset, byte,Byte, boolean, Boolean, float,Float, double, Double, String

    (3)非基本数据类型(如基本容器,其他对象等),只是拷贝了一份引用出去了,实际指向的依然是同一份,例如上的list<String>

  一句话总结就是:基本数据类型是值赋值;非基本的就是引用赋值。

2、深克隆

  创建一个全新的对象,新的对象内部所有的成员也都是全新的,只是初始化的值已经由被克隆的对象确定,但是他们是两个完全独立的对象,修改是隔离,互不影响。

下面我们来写一个简单的深克隆

import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* @Description TODO
* @Author Bert
* @Date 2019\6\10 0010
*/
public class DeepClone implements Serializable{
private String name;
private int age;
private List<String> hobbies; 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 List<String> getHobbies() {
return hobbies;
} public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
} // 深克隆 方法 1
public DeepClone deepClone(){
DeepClone deepClone = new DeepClone();
deepClone.setName(this.name);
deepClone.setAge(this.age);
//基本数据类型 重新创建
if(null != this.hobbies){
deepClone.setHobbies(new ArrayList<>(this.hobbies));
}
return deepClone;
} //深克隆 2 通过 byte字节码 ,这种方式需要 实现 Serializable
public DeepClone deepCloneByte() {
DeepClone dClone = null;
ByteArrayOutputStream bys = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bys);
oos.writeObject(this); ByteArrayInputStream bis = new ByteArrayInputStream(bys.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
dClone = (DeepClone)ois.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return dClone;
} }

  测试代码:

public static void main(String[] args) {
DeepClone deepClone = new DeepClone();
deepClone.setName("ZhangSan");
deepClone.setAge(21);
List<String> list = new ArrayList<>();
list.add("play game");
list.add("Listen music");
deepClone.setHobbies(list);
//调用第一种方式,并修改值
DeepClone deepClone1 = deepClone.deepClone();
deepClone1.getHobbies().add("fitness");
deepClone1.setAge(22);
//调用第二种方式,并修改值
DeepClone deepClone2 = deepClone.deepCloneByte();
deepClone2.getHobbies().add("Climbing mountain"); System.out.println(deepClone == deepClone1);
System.out.println(deepClone == deepClone2);
System.out.println("克隆对象中引用类型地址:"+deepClone.getHobbies());
System.out.println("克隆对象中引用类型地址:"+deepClone1.getHobbies());
System.out.println("克隆对象中引用类型地址:"+deepClone2.getHobbies());
}

  运行结果:

false
false
克隆对象中引用类型地址:[play game, Listen music]
克隆对象中引用类型地址:[play game, Listen music, fitness]
克隆对象中引用类型地址:[play game, Listen music, Climbing mountain]

  以上可以看出深克隆的对象之间修改完全不受影响。

3、原型模式运用场景

  (1)类初始化消耗资源较多。

  (2)new 产生的一个对象需要非常繁琐的过程(数据准备、访问权限等)

  (3)构造函数比较复杂。

  (4)循环体中生产大量对象时。

在 Spring 中,原型模式应用得非常广泛。例如 scope=“prototype”,在我们经常用 的 JSON.parseObject()也是一种原型模式。

4、解决深克隆破坏单例模式

  如果我们的被克隆对象是单例模式,深克隆就得破坏单例模式。

  解决方案:禁止深克隆。一是不实现Cloneable; 二是实现Cloneable ,在clone方法中返回我们的单例。

 @Override
protected Object clone() throws CloneNotSupportedException {
return INSTANCE;
}

  Cloneable 源码分析:

  以ArryList 为例,ArrayList 就实现了 Cloneable 接口

/**
* Returns a shallow copy of this <tt>ArrayList</tt> instance. (The
* elements themselves are not copied.)
*
* @return a clone of this <tt>ArrayList</tt> instance
*/
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}

  

JAVA 设计模式之 原型模式详解的更多相关文章

  1. 设计模式之 原型模式详解(clone方法源码的简单剖析)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 原型模式算是JAVA中最简单 ...

  2. JAVA 设计模式之 工厂模式详解

    一.简单工厂模式 简单工厂模式(Simple Factory Pattern)是指由一个工厂对象决定创建出哪一种产品类 的实例.属于创建型模式,但它不属于 GOF,23 种设计模式 (参考资料: ht ...

  3. Java设计模式之状态模式详解

    (本文由言念小文原创,转载请注明出处) 在实际工作中经常遇到某个对象,处于不同的状态有不同行为逻辑.且状态之间可以相互迁移的业务场景,特别是在开发通信协议栈类软件中尤为多见.<设计模式之禅> ...

  4. JAVA 设计模式之原型模式

    目录 JAVA 设计模式之原型模式 简介 Java实现 1.浅拷贝 2.深拷贝 优缺点说明 1.优点 2.缺点 JAVA 设计模式之原型模式 简介 原型模式是六种创建型设计模式之一,主要应用于创建相同 ...

  5. java设计模式4——原型模式

    java设计模式4--原型模式 1.写在前面 本节内容与C++语言的复制构造函数.浅拷贝.深拷贝极为相似,因此建议学习者可以先了解C++的该部分的相关知识,或者学习完本节内容后,也去了解C++的相应内 ...

  6. java设计模式之原型模式

    原型模式概念 该模式的思想就是将一个对象作为原型,对其进行复制.克隆,产生一个和原对象类似的新对象.java中复制通过clone()实现的.clone中涉及深.浅复制.深.浅复制的概念如下: ⑴浅复制 ...

  7. JAVA 23种开发模式详解(代码举例)

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  8. (二十三)原型模式详解(clone方法源码的简单剖析)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 原型模式算是JAVA中最简单 ...

  9. java设计模式之五原型模式(Prototype)

    原型模式虽然是创建型的模式,但是与工程模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制.克隆,产生一个和原对象类似的新对象.本小结会通过对象的复制,进行讲解.在Java中 ...

随机推荐

  1. 深度探索C++对象模型读书笔记-第六章执行期语意学

    在函数中,编译器会帮助将析构函数(Destructor) 安插在相应的位置.对于函数中的局部对象,会将析构函数安插在对象的每一个离开点. 例如: 1: void Function(int a) { 2 ...

  2. 干货满满!10分钟看懂Docker和K8S

    2010年,几个搞IT的年轻人,在美国旧金山成立了一家名叫“dotCloud”的公司. 这家公司主要提供基于PaaS的云计算技术服务.具体来说,是和LXC有关的容器技术. LXC,就是Linux容器虚 ...

  3. input 实现一次性上传文件

    在实际项目中可能会用到,上传多个文件请求一次接口,因此,主要代码 $('#tabList').on('click','.resetWorkStatus',function(){ var that = ...

  4. [转]WPF中的导航框架

    有的时候,我们需要一个支持页面跳转的UI,例如文件浏览器,开始向导等.对于这样的界面,简单的可以使用ContentControl + ContentTemplateSelector的方式来实现,但是有 ...

  5. Jmeter-【JSON Extractor】-响应结果中二级key取值

    一.请求返回样式 二.取chapter的值 三.查看结果

  6. javascript--判断语句

    1.if...else.. if(m===1){ console.log('1') }else{ console.log('X') } 一般if 里面采用类型全等的运算符. 2.switch var ...

  7. IDEA 注解开发流程

    IDEA 注解开发流程  分为以下四步  分别是 1 导入依赖 2 配置文件 applicationContext.xml 3 在需要创建对象的类上添加注解 4  测试 详细步骤和代码如下 1 导入依 ...

  8. android高级篇收录

    Android运行时性能优化 1.android启动优化 支付宝客户端架构解析:Android 客户端启动速度优化之「垃圾回收」 支付宝 App 构建优化解析:通过安装包重排布优化 Android 端 ...

  9. LeetCode 817. Linked List Components (链表组件)

    题目标签:Linked List 题目给了我们一组 linked list, 和一组 G, 让我们找到 G 在 linked list 里有多少组相连的部分. 把G 存入 hashset,遍历 lin ...

  10. docker service 集群创建

    docker service create /新建docker集群--name webwork /集群的名称--replicas 3/ 启动3个节点--network my-network/ netw ...