原型模式

原型模式:

  通过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对象一同进行了克隆。输出请遵循上述方法分析理解。

 

端:

 

posted @ 2016-03-18 11:16  再见,少年  Views(171)  Comments(0Edit  收藏  举报