浅析Java设计模式之原型模式、深拷贝、浅拷贝

一、原型模式的UML图

      

浅析Java设计模式之原型模式、深拷贝、浅拷贝_第1张图片

 

  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原则。

 

 

          

你可能感兴趣的:(软件架构和设计模式,原型模式,设计模式,深拷贝,浅拷贝)