原型模式(Prototype)

原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

形    式:原型模式有两种模式:1. 浅复制(浅克隆)2. 深复制(深克隆)
    1. 浅复制(浅克隆)

   被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。

     2. 深复制(深克隆)

被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。

 

Java的clone()方法特性:
可以用例判断克隆对象和原对象是否相等
clone方法将对象复制了一份并返回给调用者。一般而言,clone()方法满足:
①对任何的对象x,都有x.clone() !=x //克隆对象与原对象不是同一个对象
②对任何的对象x,都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一样
③如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。
 
Java中对象的克隆
①为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。
②在派生类中覆盖基类的clone()方法,并声明为public。
③在派生类的clone()方法中,调用super.clone()。
④在派生类中实现Cloneable接口。
注意:final与clone()是死对头来的

 
1.浅克隆案例
     浅克隆代码一:实现Cloneable接口
 
public class Prototype implements Cloneable {

	private String name;

	public Prototype(String name){
		this.name=name;
	};
	
	public Prototype clone(){
		Prototype p=null;
		try {
			 p=(Prototype) super.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return p;
	}
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
    
}

    浅克隆代码2:client端
  
public class PrototypeTest {

	/** 
	 * @Title: main 
	 * @Description: TODO 
	 * @param args 
	 * @return void  
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

			Prototype p1=new Prototype("原型moshi ");
			System.out.println("传统1=="+p1.getName());
			Prototype p2=p1.clone();
			System.out.println("原型1=="+p2.getName());
			
			//修改克隆对象的值
			p1.setName("gaiguo自新");
			System.out.println("传统2=="+p1.getName());
			System.out.println("原型2=="+p2.getName());			
	}

}

运行结果:
 
传统1==原型moshi 
原型1==原型moshi 
传统2==gaiguo自新
原型2==原型moshi 
再看一个浅克隆的例子
 

浅复制(浅克隆):

汽车类:

Java代码
  1. /*
  2. * 汽车类
  3. *
  4. * 浅克隆(shadow clone)的实现
  5. */
  6. public class Carimplements Cloneable {
  7. // 汽车款式
  8. public int type;
  9. // 引用的其他对象,汽车发动机
  10. public Engine engine;
  11. public Object clone() {
  12. Object clone = null;
  13. try {
  14. // 这里只是克隆的自己本身
  15. clone = super.clone();
  16. // 为什么在派生类中覆盖Object的clone()方法时,一定要调用super.clone()呢?
  17. // 因为,在运行时刻,Object中的clone()识别出你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,
  18. // 将原始对象的内容一一复制到新对象的存储空间中。
  19. } catch (CloneNotSupportedException e) {
  20. }
  21. return clone;
  22. }
  23. }
/*
 * 汽车类
 * 
 * 浅克隆(shadow clone)的实现
 */
public class Car implements Cloneable {
	
//	汽车款式
	public int type;

//	引用的其他对象,汽车发动机
	public Engine engine;

	public Object clone() {
		
		Object clone = null;
		try {

//			这里只是克隆的自己本身
			clone = super.clone();
			
//			为什么在派生类中覆盖Object的clone()方法时,一定要调用super.clone()呢?
//			因为,在运行时刻,Object中的clone()识别出你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,
//			将原始对象的内容一一复制到新对象的存储空间中。	
			
		} catch (CloneNotSupportedException e) {

		}
		return clone;
	}

}

发动机类:

Java代码
  1. /*
  2. * 汽车发动机类,汽车类中引用的对象的类
  3. */
  4. public class Engineimplements Cloneable {
  5. // 汽车发动机型号
  6. public int model;
  7. }
/*
 * 汽车发动机类,汽车类中引用的对象的类
 */
public class Engine implements Cloneable {
	
//	汽车发动机型号
	public int model;

}

客户端调用:

Java代码
  1. /*
  2. * 浅克隆(shadow clone)的调用
  3. */
  4. public class Client {
  5. public staticvoid main(String argv[])
  6. {
  7. System.out.println("-----创建汽车1-----");
  8. Car car1=new Car();
  9. car1.engine=new Engine();
  10. car1.type=1;
  11. car1.engine.model=1;
  12. System.out.println("汽车1款式:"+car1.type+"\t汽车1的发动机型号:"+car1.engine.model);
  13. System.out.println("----汽车1--克隆-->汽车2----");
  14. Car car2=(Car)car1.clone();
  15. car2.type=2;
  16. car2.engine.model=2;
  17. System.out.println("汽车2款式:"+car2.type+"\t汽车2的发动机型号:"+car2.engine.model);
  18. System.out.println("汽车1款式:"+car1.type+"\t汽车1的发动机型号:"+car1.engine.model);
  19. }
  20. }
/*
 * 浅克隆(shadow clone)的调用
 */
public class Client {
	   public static  void main(String argv[])
	   {
		 System.out.println("-----创建汽车1-----");
		 Car car1=new Car();
	     car1.engine=new Engine();
	     car1.type=1;
	     car1.engine.model=1;
	     System.out.println("汽车1款式:"+car1.type+"\t汽车1的发动机型号:"+car1.engine.model);
	     
	     System.out.println("----汽车1--克隆-->汽车2----");
	     Car car2=(Car)car1.clone();
	     car2.type=2;
	     car2.engine.model=2;
	     
	     System.out.println("汽车2款式:"+car2.type+"\t汽车2的发动机型号:"+car2.engine.model);
	     System.out.println("汽车1款式:"+car1.type+"\t汽车1的发动机型号:"+car1.engine.model);
	   }
	 }

运行结果:

Java代码
  1. -----创建汽车1-----
  2. 汽车1款式:1 汽车1的发动机型号:1
  3. ----汽车1--克隆-->汽车2----
  4. 汽车2款式:2 汽车2的发动机型号:2
  5. 汽车1款式:1 汽车1的发动机型号:2
-----创建汽车1-----
汽车1款式:1	汽车1的发动机型号:1
----汽车1--克隆-->汽车2----
汽车2款式:2	汽车2的发动机型号:2
汽车1款式:1	汽车1的发动机型号:2

根据运行结果可以发现,浅复制(浅克隆)仅仅复制所考虑的对象,而不复制它所引用的对象。
所以,当设定汽车2发动机型号为2 时,也将汽车1的发动机型号有1变成了2

因为汽车1和汽车2实际上使用的是同一个发动机

 
 
 
 

深克隆

深复制(深克隆):

怎么实现深复制(深克隆)呢?修改一下汽车类和汽车发动机类:

汽车类:

Java代码
  1. /*
  2. * 深克隆
  3. */
  4. public class Carimplements Cloneable {
  5. public int type;
  6. // 引用的其他对象
  7. public Engine engine;
  8. public Object clone() {
  9. Car temp = null;
  10. try {
  11. // 先把自己本身复制
  12. temp = (Car) super.clone();
  13. // 为了实现深度克隆,需要将对其他对象(在这里是engine)的引用都复制过去。
  14. temp.engine = (Engine) engine.clone();
  15. } catch (CloneNotSupportedException e) {
  16. // should never happen
  17. }
  18. return temp;
  19. }
  20. }
/*
 * 深克隆
 */
public class Car implements Cloneable {
	
	public int type;

//	引用的其他对象
	public Engine engine;

	public Object clone() {

		Car temp = null;
		try {

//			先把自己本身复制
			temp = (Car) super.clone();
			
//			为了实现深度克隆,需要将对其他对象(在这里是engine)的引用都复制过去。
			temp.engine = (Engine) engine.clone();
		} catch (CloneNotSupportedException e) {
			// should never happen
		}

		return temp;
	}
}

发动机类:

Java代码
  1. public class Engineimplements Cloneable {
  2. public int model;
  3. /**
  4. * 为了实现深度克隆,需要给在Lay1中被应用的对象lay2)也提供一个自己克隆自身的方法
  5. */
  6. public Object clone() {
  7. Object clone = null;
  8. try {
  9. clone = super.clone();
  10. } catch (CloneNotSupportedException e) {
  11. }
  12. return clone;
  13. }
  14. }
public class Engine implements Cloneable {
	public int model;

	/**
	 * 为了实现深度克隆,需要给在Lay1中被应用的对象lay2)也提供一个自己克隆自身的方法
	 */
	public Object clone() {
		Object clone = null;
		try {
			clone = super.clone();
		} catch (CloneNotSupportedException e) {

		}
		return clone;
	}

}

客户端调用不变。

运行结果:

Java代码
  1. -----创建汽车1-----
  2. 汽车1款式:1 汽车1的发动机型号:1
  3. ----汽车1--克隆-->汽车2----
  4. 汽车2款式:2 汽车2的发动机型号:2
  5. 汽车1款式:1 汽车1的发动机型号:1
-----创建汽车1-----
汽车1款式:1	汽车1的发动机型号:1
----汽车1--克隆-->汽车2----
汽车2款式:2	汽车2的发动机型号:2
汽车1款式:1	汽车1的发动机型号:1

根据运行结果可以发现,深复制(深克隆)把要复制的对象所引用的对象都复制了一遍。

所以,当设定汽车2发动机型号为2 时,汽车1的发动机型号还是1,没有变化

因为,汽车1和汽车2拥有了两个不同的发动机。

利用串行化来做深复制(深克隆):

汽车类

实现了串行(序列)化接口,并使用了在流中读取和写入对象。

Java代码
  1. import java.io.ByteArrayInputStream;
  2. import java.io.ByteArrayOutputStream;
  3. import java.io.IOException;
  4. import java.io.ObjectInputStream;
  5. import java.io.ObjectOutputStream;
  6. import java.io.Serializable;
  7. /*
  8. * 汽车类
  9. *
  10. * 序列化的方式实现深克隆(deep clone)
  11. */
  12. public class Carimplements Serializable {
  13. /**
  14. * serialVersionUID
  15. */
  16. private staticfinal long serialVersionUID = 1859639569305572020L;
  17. // 汽车款式
  18. public int type;
  19. // 引用的其他对象,汽车发动机
  20. public Engine engine;
  21. public Object clone() {
  22. try {
  23. // 将对象写到流里,把对象写到流里的过程是串行化(Serilization)过程
  24. ByteArrayOutputStream bo = new ByteArrayOutputStream();
  25. ObjectOutputStream oo;
  26. oo = new ObjectOutputStream(bo);
  27. oo.writeObject(this);
  28. // 从流里读出来,把对象从流中读出来的并行化(Deserialization)过程
  29. ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
  30. ObjectInputStream oi = new ObjectInputStream(bi);
  31. return (oi.readObject());
  32. } catch (ClassNotFoundException e) {
  33. // TODO Auto-generated catch block
  34. return null;
  35. } catch (IOException e) {
  36. // TODO Auto-generated catch block
  37. return null;
  38. }
  39. }
  40. }
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/*
 * 汽车类
 * 
 * 序列化的方式实现深克隆(deep clone)
 */
public class Car implements Serializable {

	/**
	 * serialVersionUID 
	 */
	private static final long serialVersionUID = 1859639569305572020L;

//	汽车款式
	public int type;

//  引用的其他对象,汽车发动机
	public Engine engine;

	public Object clone() {

		try {

//			将对象写到流里,把对象写到流里的过程是串行化(Serilization)过程

			ByteArrayOutputStream bo = new ByteArrayOutputStream();
			ObjectOutputStream oo;

			oo = new ObjectOutputStream(bo);

			oo.writeObject(this);

//			从流里读出来,把对象从流中读出来的并行化(Deserialization)过程
			ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
			ObjectInputStream oi = new ObjectInputStream(bi);
			return (oi.readObject());

		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			return null;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			return null;
		}
	}
}

汽车发动机类:

Java代码
  1. import java.io.Serializable;
  2. public class Engineimplements Cloneable, Serializable {
  3. /**
  4. * Car对象以及对象内部所有引用到的对象engine都是可串行化的
  5. */
  6. private staticfinal long serialVersionUID = -6228724315977120960L;
  7. public int model;
  8. }
import java.io.Serializable;

public class Engine implements Cloneable, Serializable {

	/**
	 * Car对象以及对象内部所有引用到的对象engine都是可串行化的
	 */
	private static final long serialVersionUID = -6228724315977120960L;

	public int model;

}

客户端调用不变。

运行结果:

Java代码
  1. -----创建汽车1-----
  2. 汽车1款式:1 汽车1的发动机型号:1
  3. ----汽车1--克隆-->汽车2----
  4. 汽车2款式:2 汽车2的发动机型号:2
  5. 汽车1款式:1 汽车1的发动机型号:1

 

根据运行结果可以发现,通过串行化的方式也实现了深复制(可克隆)。

所以,当设定汽车2发动机型号为2 时,汽车1的发动机型号还是1,没有变化

因为,汽车1和汽车2拥有了两个不同的发动机。

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值