前言

创新互联公司专业为企业提供峨边彝族网站建设、峨边彝族做网站、峨边彝族网站设计、峨边彝族网站制作等企业网站建设、网页设计与制作、峨边彝族企业网站模板建站服务,十载峨边彝族做网站经验,不只是建网站,更提供有价值的思路和整体网络服务。
23种设计模式快速记忆的请看上面第一篇,本篇和大家一起来学习原型模式,在学习原型模式之前我们需要先认识下浅拷贝和深拷贝这两个概念。
浅拷贝和深拷贝
 浅拷贝
 浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。
复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个值都会随之变化。
深拷贝
 深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。
将对象及值复制过来,两个对象修改其中任意的值另一个值不会改变。
模式定义
 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式其实就是一个对象在创建另一个可定制的对象,而且不需要指定任何创建的细节。Java提供了Coneable接口,其中有一个唯一方法Clone(),实现这个接口就可以完成原型模式了。
实例说明
 浅拷贝案例
 声明 User 实体类,需要实现 Cloneable 接口,并覆写 clone() 方法。
User 属性包括基础数据类型和引用数据类型,方便演示
- package com.niuh.designpattern.prototype;
 - /**
 - * 用户信息
 - */
 - public class User implements Cloneable {
 - // 基础数据类型
 - private int id;
 - private String name;
 - private String sex;
 - private String pwd;
 - // 引用数据类型
 - private BaseInfo baseInfo;
 - public User(int id, String name, String sex, String pwd, BaseInfo baseInfo) {
 - this.id = id;
 - this.name = name;
 - this.sex = sex;
 - this.pwd = pwd;
 - this.baseInfo = baseInfo;
 - }
 - public int getId() {
 - return id;
 - }
 - public void setId(int id) {
 - this.id = id;
 - }
 - public String getName() {
 - return name;
 - }
 - public void setName(String name) {
 - this.name = name;
 - }
 - public String getSex() {
 - return sex;
 - }
 - public void setSex(String sex) {
 - this.sex = sex;
 - }
 - public String getPwd() {
 - return pwd;
 - }
 - public void setPwd(String pwd) {
 - this.pwd = pwd;
 - }
 - public BaseInfo getBaseInfo() {
 - return baseInfo;
 - }
 - public void setBaseInfo(BaseInfo baseInfo) {
 - this.baseInfo = baseInfo;
 - }
 - @Override
 - public String toString() {
 - return "hashCode: " + super.hashCode() + ", User{" +
 - "id=" + id +
 - ", name='" + name + '\'' +
 - ", sex='" + sex + '\'' +
 - ", pwd='" + pwd + '\'' +
 - ", baseInfo=" + baseInfo +
 - '}';
 - }
 - @Override
 - protected User clone() throws CloneNotSupportedException {
 - return (User) super.clone();
 - }
 - }
 
- package com.niuh.designpattern.prototype;
 - import java.util.Date;
 - /**
 - * 基础类
 - */
 - public class BaseInfo {
 - private String desc;
 - // .......
 - public BaseInfo(String desc) {
 - this.desc = desc;
 - }
 - public String getDesc() {
 - return desc;
 - }
 - public void setDesc(String desc) {
 - this.desc = desc;
 - }
 - @Override
 - public String toString() {
 - return "BaseInfo{" +
 - "desc=" + desc +
 - '}';
 - }
 - }
 
- package com.niuh.designpattern.prototype;
 - /**
 - * 原型设计模式
 - */
 - public class PrototypePattern {
 - public static void main(String[] args) throws CloneNotSupportedException {
 - BaseInfo baseInfo = new BaseInfo("张三");
 - User user1 = new User(1, "张三", "男", "123456", baseInfo);
 - // new User ......
 - // 克隆机制
 - User user2 = user1.clone();
 - user2.setId(2);
 - user2.setName("李四");
 - BaseInfo baseInfo1 = user2.getBaseInfo();
 - baseInfo1.setDesc("李四");
 - System.out.println(user1);
 - System.out.println(user2);
 - }
 - }
 
输出结果如下:
由输出的结果可见,通过 user1.clone() 拷贝对象后得到的 user2,和 user1 是两个不同的对象,HashCode 值不一样。user1 和 user2 的基础数据类型的修改互不影响,而引用类型 baseInfo 修改后是会有影响的。
深拷贝案例
 通过上面的例子可以看到,浅拷贝会带来数据安全方面的隐患,例如我们只是想修改了 user2 的 baseInfo,但是 user1 的 baseInfo 也被修改了,因为它们都是指向的同一个地址。所以,此种情况下,我们需要用到深拷贝。
深拷贝,在拷贝引用类型成员变量时,为引用类型的数据成员另辟了一个独立的内存空间,实现真正内容上的拷贝。
对于 User 的引用类型的成员变量 BaseInfo ,需要实现 Cloneable 并重写 clone() 方法。
- package com.niuh.designpattern.prototype;
 - import java.util.Date;
 - /**
 - * 基础类
 - */
 - public class BaseInfo implements Cloneable {
 - private String desc;
 - // .......
 - public BaseInfo(String desc) {
 - this.desc = desc;
 - }
 - public String getDesc() {
 - return desc;
 - }
 - public void setDesc(String desc) {
 - this.desc = desc;
 - }
 - @Override
 - public String toString() {
 - return "BaseInfo{" +
 - "desc=" + desc +
 - '}';
 - }
 - @Override
 - protected BaseInfo clone() throws CloneNotSupportedException {
 - //BaseInfo 如果也有引用类型的成员属性,也应该和 User 类一样实现
 - return (BaseInfo) super.clone();
 - }
 - }
 
在 User 的 clone() 方法中,需要拿到拷贝自己后产生的新的对象,然后对新的对象的引用类型再调用拷贝操作,实现对引用类型成员变量的深拷贝。
- package com.niuh.designpattern.prototype;
 - /**
 - * 用户信息
 - */
 - public class User implements Cloneable {
 - // 基础数据类型
 - private int id;
 - private String name;
 - private String sex;
 - private String pwd;
 - // 引用数据类型
 - private BaseInfo baseInfo;
 - public User(int id, String name, String sex, String pwd, BaseInfo baseInfo) {
 - this.id = id;
 - this.name = name;
 - this.sex = sex;
 - this.pwd = pwd;
 - this.baseInfo = baseInfo;
 - }
 - public int getId() {
 - return id;
 - }
 - public void setId(int id) {
 - this.id = id;
 - }
 - public String getName() {
 - return name;
 - }
 - public void setName(String name) {
 - this.name = name;
 - }
 - public String getSex() {
 - return sex;
 - }
 - public void setSex(String sex) {
 - this.sex = sex;
 - }
 - public String getPwd() {
 - return pwd;
 - }
 - public void setPwd(String pwd) {
 - this.pwd = pwd;
 - }
 - public BaseInfo getBaseInfo() {
 - return baseInfo;
 - }
 - public void setBaseInfo(BaseInfo baseInfo) {
 - this.baseInfo = baseInfo;
 - }
 - @Override
 - public String toString() {
 - return "hashCode: " + super.hashCode() + ", User{" +
 - "id=" + id +
 - ", name='" + name + '\'' +
 - ", sex='" + sex + '\'' +
 - ", pwd='" + pwd + '\'' +
 - ", baseInfo=" + baseInfo +
 - '}';
 - }
 - @Override
 - protected User clone() throws CloneNotSupportedException {
 - // 深拷贝
 - User user = (User) super.clone();
 - user.baseInfo = baseInfo.clone();
 - return user;
 - }
 - }
 
与上面的使用方式一样,输出结果如下:
由输出结果可见,深拷贝后,不管是基础数据类型还是引用类型的成员变量,修改其值都不会相互造成影响。
序列化机制实现深拷贝
 需要在 User 类实现 Serializable,成员类型(BaseInfo)也需要实现 Serializable 接口。
- package com.niuh.designpattern.prototype;
 - import java.io.ByteArrayInputStream;
 - import java.io.ByteArrayOutputStream;
 - import java.io.IOException;
 - import java.io.ObjectInputStream;
 - import java.io.ObjectOutputStream;
 - import java.io.Serializable;
 - /**
 - * 用户信息
 - */
 - public class User implements Cloneable , Serializable {
 - // 基础数据类型
 - private int id;
 - private String name;
 - private String sex;
 - private String pwd;
 - // 引用数据类型
 - private BaseInfo baseInfo;
 - public User(int id, String name, String sex, String pwd, BaseInfo baseInfo) {
 - this.id = id;
 - this.name = name;
 - this.sex = sex;
 - this.pwd = pwd;
 - this.baseInfo = baseInfo;
 - }
 - public int getId() {
 - return id;
 - }
 - public void setId(int id) {
 - this.id = id;
 - }
 - public String getName() {
 - return name;
 - }
 - public void setName(String name) {
 - this.name = name;
 - }
 - public String getSex() {
 - return sex;
 - }
 - public void setSex(String sex) {
 - this.sex = sex;
 - }
 - public String getPwd() {
 - return pwd;
 - }
 - public void setPwd(String pwd) {
 - this.pwd = pwd;
 - }
 - public BaseInfo getBaseInfo() {
 - return baseInfo;
 - }
 - public void setBaseInfo(BaseInfo baseInfo) {
 - this.baseInfo = baseInfo;
 - }
 - @Override
 - public String toString() {
 - return "hashCode: " + super.hashCode() + ", User{" +
 - "id=" + id +
 - ", name='" + name + '\'' +
 - ", sex='" + sex + '\'' +
 - ", pwd='" + pwd + '\'' +
 - ", baseInfo=" + baseInfo +
 - '}';
 - }
 - @Override
 - protected User clone() throws CloneNotSupportedException {
 - // 深拷贝
 - // User user = (User) super.clone();
 - // user.baseInfo = baseInfo.clone();
 - // return user;
 - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
 - try (ObjectOutputStream oos = new ObjectOutputStream(byteArrayOutputStream)) {
 - oos.writeObject(this);
 - } catch (IOException e) {
 - e.printStackTrace();
 - }
 - ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
 - try (ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream)) {
 - try {
 - User user = (User) ois.readObject();
 - return user;
 - } catch (ClassNotFoundException e) {
 - e.printStackTrace();
 - }
 - } catch (IOException e) {
 - e.printStackTrace();
 - }
 - return null;
 - }
 - }
 
这个时候并没有使用Java深拷贝,改变成员属性Baseinfo,也能保存对象的独立性。
通过序列化机制来完成深拷贝不推荐使用,因为序列化操作是CPU密集型,解析流是比较消耗性能,速度会比较慢
优点
缺点
应用场景
 当代码不应该依赖于需要复制的对象的具体类时,请使用Prototype模式。
源码中的应用
- #Spring
 - org.springframework.beans.factory.support.AbstractBeanDefinition
 - #JDK
 - java.util.Arrays
 - java.util.ArrayList
 - ......
 
ArrayList中的使用
 ArrayList也有clone()方法,如下
- @Override
 - public Object clone() {
 - try {
 - ArrayList> result = (ArrayList>) super.clone();
 - result.array = array.clone();
 - return result;
 - } catch (CloneNotSupportedException e) {
 - throw new AssertionError();
 - }
 - }
 
ArrayList的Clone浅复制的巧妙使用
 当你需要使用remove方法移除掉集合中的对象,而非要修改集合中的对象的时候,可以选择使用。
- //添加两个元素
 - Student stJack=new Student("Jack", 13);
 - Student stTom=new Student("Tom", 15);
 - list.add(stJack);
 - list.add(stTom);
 - //克隆
 - ArrayList
 listCopy=(ArrayList ) list.clone(); - //移除且不修改
 - listCopy.remove(1);
 - System.out.println(list);
 - System.out.println(listCopy);
 
移除且不修改集合中的元素,只是在List内部的数组中移除了指向元素的地址,可以放心的使用clone。
PS:以上代码提交在 Github :https://github.com/Niuh-Study/niuh-designpatterns.git
                新闻标题:设计模式系列—原型模式
                
                网站网址:http://www.csdahua.cn/qtweb/news47/206847.html
            
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网