博客
关于我
浅析Java设计模式之原型模式、深拷贝、浅拷贝
阅读量:121 次
发布时间:2019-02-27

本文共 6466 字,大约阅读时间需要 21 分钟。

一、原型模式的UML图

      

 

  ProtoType:  原型类,声明一个克隆自己的接口。

  ConcreatePrototype: 具体的原型类,是实现克隆自己的操作。

 Client: 让一个原型对象克隆自己,从而产生一个新的对象。对象的属性完全相同。

 

 

二、 原型模式解决克隆羊问题

         应用案例:

         现在需要将一头绵羊克隆多个,绵羊要长的一模一样,请编写程序实现。

        1. 传统方式实现

package com.exam.prototypecommon;/** *author:bingbing *日期:2020年5月6日 *时间:下午11:15:36 *绵羊 */public class Sheep {			private String name;		private int age;		private String color;		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;	}	@Override	public String toString() {		return "Sheep [name=" + name + ", age=" + age + ", color=" + color + "]";	}		}

        测试类:

package com.exam.prototypecommon;/** *author:bingbing *日期:2020年5月6日 *时间:下午11:18:33 *克隆绵羊 */public class Test {		public static void main(String[] args) {				Sheep sheep=new Sheep("多利",1,"白色");		Sheep sheep1=new Sheep(sheep.getName(),sheep.getAge(),sheep.getColor());		Sheep sheep2=new Sheep(sheep1.getName(),sheep1.getAge(),sheep1.getColor());				System.out.println("sheep:"+sheep);		System.out.println("sheep1:"+sheep1);		System.out.println("sheep2:"+sheep2);			}}

  注: 最终看的是属性,因此需要重写一下toString()方法。

打印结果:

sheep:Sheep [name=多利, age=1, color=白色]

sheep1:Sheep [name=多利, age=1, color=白色]
sheep2:Sheep [name=多利, age=1, color=白色]

 

 2. 使用浅拷贝的方式实现克隆羊问题

       浅拷贝介绍 

        1) 对于数据类型是基本类型的成员变量,将原型的对象属性,复制一份出来,给新的对象,相当于是值传递。

        2) 对于数据类型是引用数据类型的成员变量,那么会进行引用传递,比如是成员变量是某个类的对象、数组等,也就是将该成员变量的引用值( 内存地址),复制一份出来给新的对象。实际上新克隆出来的对象的成员变量的引用和原对象的成员变量的引用都指向了同一个实例。在这种情况下,一个对象修改其成员变量,那么也会影响到另一个对象的该成员变量值,改变的是引用值

       3) 浅拷贝,默认使用的方法是clone()方法来实现。

       4)  原对象需要实现Cloneable接口。

  

package com.exam.prototype.improve;/** *author:bingbing *日期:2020年5月7日 *时间:上午6:31:44 */public class Sheep implements Cloneable{			private String name;		private int age;		private String color;		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;	}	@Override	public String toString() {		return "Sheep [name=" + name + ", age=" + age + ", color=" + color + "]";	}			@SuppressWarnings("null")	@Override	protected Object clone() throws CloneNotSupportedException {		Sheep sheep1=null;				try {			sheep1=(Sheep)super.clone();						return sheep1;					}catch(Exception e) {			  throw new RuntimeException(e.getMessage());		}	}}

   测试类:

    

package com.exam.prototype.improve;import com.exam.prototype.improve.Sheep;/** *author:bingbing *日期:2020年5月7日 *时间:上午6:37:05 *浅拷贝 */public class Test {		public static void main(String[] args) {				Sheep sheep=new Sheep("多利",1,"白色");		try {	     System.out.println(sheep.clone());		     System.out.println(sheep.clone());		     System.out.println(sheep.clone());		     System.out.println(sheep.clone());			} catch (CloneNotSupportedException e) {			// TODO Auto-generated catch block			e.printStackTrace();		}			}}

 

打印结果:

Sheep [name=多利, age=1, color=白色]

Sheep [name=多利, age=1, color=白色]
Sheep [name=多利, age=1, color=白色]
Sheep [name=多利, age=1, color=白色]
 

 

3. 使用深拷贝的方式实现克隆羊问题

      深拷贝介绍    

      1) 复制对象的所有基本数据类型的成员变量值

      2) 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变 量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象进行拷贝
      3) 深拷贝实现方式1
:重写
clone
方法来实现深拷贝
      4) 深拷贝实现方式2
:通过对象序列化实现深拷贝
(
推荐
)
     
    
public class DeepProtoType implements Serializable, Cloneable{		public String name; 	public DeepCloneableTarget deepCloneableTarget;	public DeepProtoType() {		super();	}		//重写克隆方法	@Override	protected Object clone() throws CloneNotSupportedException {				Object deep = null;		deep = super.clone(); 		DeepProtoType deepProtoType = (DeepProtoType)deep;		deepProtoType.deepCloneableTarget  = (DeepCloneableTarget)deepCloneableTarget.clone();				// TODO Auto-generated method stub		return deepProtoType;	}		//对象序列化的方式	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 exception			e.printStackTrace();			return null;		} finally {			try {				//关闭流				bos.close();				oos.close();				bis.close();				ois.close();			} catch (Exception e2) {				// TODO: handle exception				System.out.println(e2.getMessage());			}		}			}	}

 

       
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;	}			@Override	protected Object clone() throws CloneNotSupportedException {		return super.clone();	}}

 测试类:

public static void main(String[] args) throws Exception {		// TODO Auto-generated method stub		DeepProtoType p = new DeepProtoType();		p.name = "多利羊";		p.deepCloneableTarget = new DeepCloneableTarget("新的多利羊", "CloneSheep");						//重写克隆方式				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());			//对象序列化方式		DeepProtoType p3 = (DeepProtoType) p.deepClone();				System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());		System.out.println("p3.name=" + p.name + "p3.deepCloneableTarget=" + p3.deepCloneableTarget.hashCode());		}

打印结果:

p.name=多利羊p.deepCloneableTarget=1829164700

p2.name=多利羊p2.deepCloneableTarget=2018699554
p.name=多利羊p.deepCloneableTarget=1829164700
p3.name=多利羊p3.deepCloneableTarget=2093631819
 

 
      

    

    

三、使用原型模式需要注意的问题

     1.  创建新的对象比较复杂时,使用原型模式,可以一定大大减少代码量,并且能够提升效率。

     2.  不用重新初始化对象,而是获取了对象运行时的状态。

     3.  如果原对象发生变化,那么其它克隆的对象也会发生变化,无需修改代码。 

     4.  在使用深拷贝时,可能需要写很多复杂的代码。 

     5.  需要为每个类配备一个克隆方法,对已有的类进行改造时,需要修改其源代码,那么违背了OCP原则。

 

 

          

转载地址:http://twwb.baihongyu.com/

你可能感兴趣的文章
MySQL 数据库设计总结
查看>>
Mysql 数据库重置ID排序
查看>>
Mysql 数据类型一日期
查看>>
MySQL 数据类型和属性
查看>>
mysql 敲错命令 想取消怎么办?
查看>>
Mysql 整形列的字节与存储范围
查看>>
mysql 断电数据损坏,无法启动
查看>>
MySQL 日期时间类型的选择
查看>>
Mysql 时间操作(当天,昨天,7天,30天,半年,全年,季度)
查看>>
MySQL 是如何加锁的?
查看>>
MySQL 是怎样运行的 - InnoDB数据页结构
查看>>
mysql 更新子表_mysql 在update中实现子查询的方式
查看>>
MySQL 有什么优点?
查看>>
mysql 权限整理记录
查看>>
mysql 权限登录问题:ERROR 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using password: YES)
查看>>
MYSQL 查看最大连接数和修改最大连接数
查看>>
MySQL 查看有哪些表
查看>>
mysql 查看锁_阿里/美团/字节面试官必问的Mysql锁机制,你真的明白吗
查看>>
MySql 查询以逗号分隔的字符串的方法(正则)
查看>>
MySQL 查询优化:提速查询效率的13大秘籍(避免使用SELECT 、分页查询的优化、合理使用连接、子查询的优化)(上)
查看>>