您的位置:首页 > 其它

原型模式

2016-03-18 11:16 225 查看
原型模式:

  通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。

   java中的克隆技术,以某个对象为原型,复制出新的对象。新的对象具有原型对象的特性。

     优势有:效率高(直接克隆、避免了重新执行构造过程步骤)

  克隆类似于new,但是不同于new。new创建新的对象属性采用的是默认值。克隆出的对象的属性

  值完全和原型对象相同。并且克隆出的新对象改变不会影响原型对象(深克隆不会,浅克隆可能会)。然后,在修改克隆对象的值。

原型模式实现:

  Cloneable接口的clone方法

  Prototype模式中实现起来最困难的地方就是内存的复制操作,所幸在Java中为我们提供了clone()方法

  替我们做了绝大部分事情。

java提供了对于克隆的支持,想要实现克隆,必须实现Cloneable接口,该接口是个空接口,里面没有方法,此外还需要重写Object类的本地clone()方法。Cloneable接口的代码如下:

 

/*
* Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package java.lang;
/**
* A class implements the <code>Cloneable</code> interface to
* indicate to the {@link java.lang.Object#clone()} method that it
* is legal for that method to make a
* field-for-field copy of instances of that class.
* <p>
* Invoking Object's clone method on an instance that does not implement the
* <code>Cloneable</code> interface results in the exception
* <code>CloneNotSupportedException</code> being thrown.
* <p>
* By convention, classes that implement this interface should override
* <tt>Object.clone</tt> (which is protected) with a public method.
* See {@link java.lang.Object#clone()} for details on overriding this
* method.
* <p>
* Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
* Therefore, it is not possible to clone an object merely by virtue of the
* fact that it implements this interface.  Even if the clone method is invoked
* reflectively, there is no guarantee that it will succeed.
*
* @author  unascribed
* @see     java.lang.CloneNotSupportedException
* @see     java.lang.Object#clone()
* @since   JDK1.0
*/
public interface Cloneable {
}


  一个克隆的实现:

package com.oj;

import java.util.Date;

/**
* @author We.lxk
*
*/
public class Sheep implements Cloneable{
private String sname;
private Date date;

public Sheep() {
// TODO Auto-generated constructor stub
}

public Sheep(String sname, Date date) {
super();
this.sname = sname;
this.date = date;
}

public String getSname() {
return sname;
}

public void setSname(String sname) {
this.sname = sname;
}

public Date getDate() {
return date;
}

public void setDate(Date date) {
this.date = date;
}

@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();		//直接调用object对象的clone()方法
return obj;
}
}


 测试代码:

package com.oj;

import java.util.Date;

public class Client {
public static void main(String[] args) throws Exception {
Date d = new Date(123123123123123L);
Sheep s = new Sheep("少利",d);
System.out.println(s);

Sheep s2 = (Sheep) s.clone();
System.out.println(s2);

System.out.println(s==s2);

Sheep s3 = s;
System.out.println(s==s3);

s2.setSname("呵呵");
System.out.println("s: "+s.getSname()+" , "+s.getDate()+"    s2: "+s2.getSname()+" , "+s2.getDate());
d.setTime(123123123123L);
System.out.println("s: "+s.getSname()+" , "+s.getDate()+"    s2: "+s2.getSname()+" , "+s2.getDate());
}
}


 测试输出:

com.oj.Sheep@16bd8ea
com.oj.Sheep@16e1fb1
false
true
s: 少利 , Mon Aug 14 11:32:03 CST 5871 s2: 呵呵 , Mon Aug 14 11:32:03 CST 5871
s: 少利 , Mon Nov 26 08:52:03 CST 1973 s2: 呵呵 , Mon Nov 26 08:52:03 CST 1973

通过输出可以发现,这个实现是浅克隆,s2克隆了s,克隆时只是把s中属性的值(引用类型,指向了一个地址)在堆中另外复制了一份,即把地址复制了一份,所以这个时候s和s2指向了堆中不同的位置,运用==比较时才会false,因为地址不一样了,这个地址所存储的值并没有复制,其中的Date d;仍然等于说是两个对象共用了一份,因此当你直接改变d的值得时候表现为s和s2两个输出的日期同时发生了变化,当你采用s.setDate(new Date(123L))时,这是在堆中新建立了一个Date对象,相当于同d已经脱离了,这是d已经只有s2中的date指向,s中的date指向了这个在堆中新建立的对象了,这时两者才算是脱离了;把s2直接赋值给s3时,两个地址引用指向了同一个堆中对象的位置,这个比较是相等的。

下面进行深克隆

package com.oj;

import java.util.Date;

/**
* @author We.lxk
*
*/
public class Sheep2 implements Cloneable{
private String sname;
private Date date;

public Sheep2() {
// TODO Auto-generated constructor stub
}

public Sheep2(String sname, Date date) {
super();
this.sname = sname;
this.date = date;
}

public String getSname() {
return sname;
}

public void setSname(String sname) {
this.sname = sname;
}

public Date getDate() {
return date;
}

public void setDate(Date date) {
this.date = date;
}

@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();		//直接调用object对象的clone()方法
Sheep2 s = (Sheep2) obj;
s.date = (Date) this.date.clone();
return obj;
}
}


 测试

package com.oj;

import java.util.Date;

public class Client2 {
public static void main(String[] args) throws Exception {
Date d = new Date(123123123123123L);
Sheep2 s = new Sheep2("少利",d);
System.out.println(s);

Sheep2 s2 = (Sheep2) s.clone();
System.out.println(s2);

System.out.println(s==s2);

Sheep2 s3 = s;
System.out.println(s==s3);

s2.setSname("呵呵");
System.out.println("s: "+s.getSname()+" , "+s.getDate()+"    s2: "+s2.getSname()+" , "+s2.getDate());
d.setTime(123123L);
System.out.println("s: "+s.getSname()+" , "+s.getDate()+"    s2: "+s2.getSname()+" , "+s2.getDate());
s2.setDate(new Date(123123123123L));
System.out.println("s: "+s.getSname()+" , "+s.getDate()+"    s2: "+s2.getSname()+" , "+s2.getDate());
}
}


  输出:

com.oj.Sheep2@16bd8ea
com.oj.Sheep2@16e1fb1
false
true
s: 少利 , Mon Aug 14 11:32:03 CST 5871 s2: 呵呵 , Mon Aug 14 11:32:03 CST 5871
s: 少利 , Thu Jan 01 08:02:03 CST 1970 s2: 呵呵 , Mon Aug 14 11:32:03 CST 5871
s: 少利 , Thu Jan 01 08:02:03 CST 1970 s2: 呵呵 , Mon Nov 26 08:52:03 CST 1973

此时,已经完全将s里的date和s2的date完全分离了,因为在克隆代码里连同date对象一同进行了克隆。输出请遵循上述方法分析理解。

端:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: