原型模式(Prototype)

来源:互联网 发布:用源码建网站 编辑:程序博客网 时间:2024/06/05 11:04

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

形    式:原型模式有两种模式: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 blocke.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 stubPrototype 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. }

发动机类:

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

客户端调用:

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. }

运行结果:

Java代码
  1. -----创建汽车1-----
  2. 汽车1款式:1 汽车1的发动机型号:1
  3. ----汽车1--克隆-->汽车2----
  4. 汽车2款式:2 汽车2的发动机型号:2
  5. 汽车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. }

发动机类:

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. }

客户端调用不变。

运行结果:

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拥有了两个不同的发动机。

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

汽车类

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

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 staticfinallong 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. }

汽车发动机类:

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

客户端调用不变。

运行结果:

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拥有了两个不同的发动机。