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中 ...
随机推荐
- visual studio snippet备忘
一.C++ classheadercpp.snippet <?xml version="1.0" encoding="utf-8"?> <Co ...
- Download Kali Linux
https://www.kali.org/downloads/
- JS分支结构与循环结构
1.分支结构 ①if语句 语法结构 if (/* 条件表达式 */) { // 执行语句 } if (/* 条件表达式 */){ // 成立执行语句 } else { // 否则执行语句 } ...
- C++11中的技术剖析(萃取技术)
从C++98开始萃取在泛型编程中用的特别多,最经典的莫过于STL.STL中的拷贝首先通过萃取技术识别是否是已知并且支持memcpy类型,如果是则直接通过内存拷贝提高效率,否则就通过类的重载=运算符,相 ...
- smarty基础总结
前提: 1. 部署smarty模板目录: 2. 编写Smarty类的子类,定制好template_dir.compile_dir.config_dir.cache_dir.left_delimiter ...
- Android中onTouch方法的执行过程以及和onClick执行发生冲突的解决办法
$*********************************************************************************************$ 博主推荐 ...
- NSDateFormatter 今年日期格式化成字符串是明年日期问题?
在项目里我要是把NSDate格式化成字符串 我的format是@"YYYY年MM月dd日 HH:mm" 传入日期2013-12-30 15:00:00后,返回给我的字符串是 201 ...
- Try running RemoteDll as Administrator
在使用RemoteDll注入动态库的时候发现注入有的动态库会提示下面的错误, LoadLibrary on remote process [1968 - Explorer.exe] failed. T ...
- 日常 java+雅思+训练题1
今天主要学了一些类似c中的一些语句,java也是一样类似的,只有一些点需要稍微注意一下,一些语句是新增的需要知道. 完完全全新学的知识就是class和instance的区别.如何创建实例.数据的封装. ...
- python简介与安装
Python简介和环境搭建 于 20世纪80年代末,Guido van Rossum发明了Python,初衷据说是为了打发圣诞节的无趣.1991年首次发布,是ABC语言的继承,同时也是一种脚本语言.取 ...