JAVA 设计模式之 原型模式详解
原型模式(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 设计模式之 原型模式详解的更多相关文章
- 设计模式之 原型模式详解(clone方法源码的简单剖析)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 原型模式算是JAVA中最简单 ...
- JAVA 设计模式之 工厂模式详解
一.简单工厂模式 简单工厂模式(Simple Factory Pattern)是指由一个工厂对象决定创建出哪一种产品类 的实例.属于创建型模式,但它不属于 GOF,23 种设计模式 (参考资料: ht ...
- Java设计模式之状态模式详解
(本文由言念小文原创,转载请注明出处) 在实际工作中经常遇到某个对象,处于不同的状态有不同行为逻辑.且状态之间可以相互迁移的业务场景,特别是在开发通信协议栈类软件中尤为多见.<设计模式之禅> ...
- JAVA 设计模式之原型模式
目录 JAVA 设计模式之原型模式 简介 Java实现 1.浅拷贝 2.深拷贝 优缺点说明 1.优点 2.缺点 JAVA 设计模式之原型模式 简介 原型模式是六种创建型设计模式之一,主要应用于创建相同 ...
- java设计模式4——原型模式
java设计模式4--原型模式 1.写在前面 本节内容与C++语言的复制构造函数.浅拷贝.深拷贝极为相似,因此建议学习者可以先了解C++的该部分的相关知识,或者学习完本节内容后,也去了解C++的相应内 ...
- java设计模式之原型模式
原型模式概念 该模式的思想就是将一个对象作为原型,对其进行复制.克隆,产生一个和原对象类似的新对象.java中复制通过clone()实现的.clone中涉及深.浅复制.深.浅复制的概念如下: ⑴浅复制 ...
- JAVA 23种开发模式详解(代码举例)
设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...
- (二十三)原型模式详解(clone方法源码的简单剖析)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 原型模式算是JAVA中最简单 ...
- java设计模式之五原型模式(Prototype)
原型模式虽然是创建型的模式,但是与工程模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制.克隆,产生一个和原对象类似的新对象.本小结会通过对象的复制,进行讲解.在Java中 ...
随机推荐
- Python学习笔记(八)——正则表达式
正则表达式 \d表示匹配一个数字 例如,1\d\d可以匹配以1开头的三位数字 \w可以匹配一个字母或者数字 例如,\d\w可以匹配12,1A等 .可以匹配任意字符 例如,py.表示pyc.pya等 * ...
- vue 外卖app(3) 引入阿里图标
1.登陆阿里图标官网 2.点击搜索按钮,输入你想要搜索的图标,加入购物车,保存到项目中 3.在项目中使用
- 解决在移动端上 click事件延迟300 毫秒的问题 fastclick.js
1 为什么会发生延迟300毫秒的问题 移动设备上的浏览器默认会在用户点击屏幕大约延迟300毫秒后才会触发点击事件,这是为了检查用户是否在做双击.为了能够立即响应用户的点击事件,才有了FastClick ...
- Linux(二)高级文本处理
一.cut (cut 命令可以从一个文本文件或者文本流中提取文本列 ) 1.cut语法 cut -d '分隔字符' -f fields 用于有特定分隔字符 cut -c 字符区间 ...
- 带你走进webpack世界,成为webpack头号玩家。
最近朋友圈被<头号玩家>刷爆了,斯皮尔伯格一个资深电影导演,把对过去经典的致敬,对未来的憧憬浓缩在这一部电影中,可以说让观众燃了起来. 观望整个前端开发,不断的演化,发展迅速.前端开发从最 ...
- 虚拟IP---Linux下一个网卡配置多个IP
转:http://blog.csdn.net/turkeyzhou/article/details/16971225 Linux下配置网卡ip别名何谓ip别名?用windows的话说,就是为一个网卡配 ...
- ncurses库的介绍与安装
Frm: http://blog.csdn.net/Mary_Jane/article/details/50769631 介绍 ncurses(new curses)是一套编程库,它提供了一系列的函数 ...
- 拾遗:{rpm、yum及源码方式管理软件包}
一.yum配置文件位置 /etc/yum.conf /etc/yum.repos.d/*.repo 二.yum常用命令 install pkgs reinstall pkgs update pkgs ...
- 分布式存储glusterfs
什么是glusterfs? Glusterfs是一个开源分布式文件系统,具有强大的横向扩展能力,可支持数PB存储容量的数干客户端,通过网络互联成一个并行的网络文件系统.具有可扩展性.高性能.高可用性等 ...
- Maven精选系列--classifier元素妙用
首先来看这么一个依赖 <dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json- ...