设计模式之原型模式

来源:互联网 发布:手机淘宝查看退货率 编辑:程序博客网 时间:2024/05/20 17:25

一、定义
通过原型实例指定创建对象的种类,并通过拷贝这些原型实例构建新的对象。(我觉简单的说,就是一种更快更省资源的创建新的
对象的方法)

二、实例
定义什么的总是难懂,还是上实例吧!
定义一个Ball类型,实现Cloneable接口,使得这个类的对象能够被克隆。

public class Ball implements Cloneable{ public int id = -1; public String teststring ; public int[] num ; public ArrayList<String> list = new ArrayList<String>(); public T t ;  @Override protected Object clone() throws CloneNotSupportedException {  Ball ball = null ;  try {   ball = (Ball) super.clone();  } catch (CloneNotSupportedException e) {   e.printStackTrace();  }  return ball ; }}//T类型class T{ public int t = 0;}
测试代码如下:
Ball ball = new Ball();  ball.setId(0);  for(int i=1;i<100;i++){   try {  Ball cloneball =  (Ball)ball.clone();    System.out.println(cloneball.id);   } catch (CloneNotSupportedException e) {    // TODO Auto-generated catch block    e.printStackTrace();   }  }

运行结果为:0

三、理论知识
3.1使用场景
原型模式很简单,基本上就是实现以下clone方法就好了,而且代码基本都是一样的。
3.2和new的区别
clone出来的对象是不经过构造函数构造的。也就是说Ball cloneball = (Ball)ball.clone()这句话没有用到构造函数就直接 定义了一个新的对象出来。
3.3clone出的对象的来源
clone方法是从内存中直接拷贝一个对象的数据到新开辟的内存空间中。

四、两种拷贝方式浅拷贝和深拷贝
4.1 区别
浅拷贝:在执行clone来创建对象的时候,新出来的对象其实是和原对象共享数组和引用的(除了基本数据类型)。
深拷贝:用clone生成对象后,这个对象是完全独立的,它的变量不会被其他clone出来的或者原型对象修改。

4.2实例4.2.1浅拷贝:看下面的测试函数:
System.out.println("ball信息:");  System.out.println("id:"+ball.id+" num:"+ball.num[0]+" "+ball.num[1]+" T:"+ball.t.t+" list[0]:"+ball.list.get(0)+" string:"+ball.teststring);  System.out.println("cloneball信息:");  System.out.println("id:"+cloneball.id+" num:"+cloneball.num[0]+" "+cloneball.num[1]+" T:"+cloneball.t.t+" list[0]:"+    cloneball.list.get(0)+" string:"+cloneball.teststring);  System.out.println("两者的teststring地址是否相同:"+(ball.teststring == cloneball.teststring));  System.out.println("修改ball信息:");  ball.id = 2;  ball.num[0] = 2;  ball.num[1] = 3;  ball.t.t = 2;  ball.list.remove(0);  ball.teststring = "i am ball after change!" ;  ball.list.add("i am the first string ball.list after change !");  System.out.println("id:"+ball.id+" num:"+ball.num[0]+" "+ball.num[1]+" T:"+ball.t.t+" list[0]:"+ball.list.get(0)+" string:"+ball.teststring);  System.out.println("此时cloneball的信息变化为:");  System.out.println("id:"+cloneball.id+" num:"+cloneball.num[0]+" "+cloneball.num[1]+" T:"+cloneball.t.t+" list[0]:"+    cloneball.list.get(0)+" string:"+cloneball.teststring);
    它的运行结果如下:
ball信息:id:1 num:1 2 T:1 list[0]:i am the first string ball.list string:i am ball!cloneball信息:id:1 num:1 2 T:1 list[0]:i am the first string ball.list string:i am ball!两者的teststring地址是否相同:true修改ball信息:id:2 num:2 3 T:2 list[0]:i am the first string ball.list after change ! string:i am ball after change!此时cloneball的信息变化为:id:1 num:2 3 T:2 list[0]:i am the first string ball.list after change ! string:i am ball!

仔细对比一下可以发现,修改ball中的基本数据类型变量id(int型)、teststring(string),不会导致cloneball中的
相应的变量改变,但是修改list(ArrayList)和num(int[])时就会导致cloneball中变量也改变。这就是浅拷贝。
(注意string类型的变量,在cloneball刚生成的时候里面的teststring和ball中的teststring是同一个东西,他们的地址是一样的,
但是一方的改变对另一方无影响,所以在这里把string也当做普通的数据类型处理)。
我觉得在堆里面的变量在克隆的时候都是共享的,而栈里面的东西都是会重新建立一个。

    4.2.1 深拷贝        就是在拷贝对象的时候将原型类中所有的引用对象再拷贝一遍。clone方法改成:
protected Object clone() throws CloneNotSupportedException {  Ball ball = null ;  try {   ball = (Ball) super.clone();   ball.list = (ArrayList<String>) this.list.clone();   ball.t = new T();  } catch (CloneNotSupportedException e) {   e.printStackTrace();  }  return ball ; }
0 0