您的位置:首页 > 其它

23种设计模式之原型模式(二)

2015-06-18 09:52 225 查看
我们接着上面的接着研究:

是把sendMail()修改成多线程的问题,但是改成多线程还是有问题呀,产生第一封邮件对象,放到线程一中运行,还没有发送出去;线程二也启动了,直接就把对象mail的收件人地址称谓全都改掉了,线程就不安全了。说道这里,你会说这有n种方式去解决,其中一种就是使用一种新型模式来解决这个问题:通过对象的复制功能来解决这个问题。

我们只需要给Mail类增加一个Cloneable接口(java自带的接口),Mail实现了这个接口后,在Mail类中覆写了clone方法,我们来看Mail类的改变:

package demo;

public class Mail implements Cloneable{
	private String receiver;
	private String subject;
	private String appellation;
	private String context;
	private String tail;
	public Mail(AdvTemplate advTemplate) {
		this.context = advTemplate.getAdvContext();
		this.subject = advTemplate.getAdvSubject();
	}
	public String getReceiver() {
		return receiver;
	}
	public void setReceiver(String receiver) {
		this.receiver = receiver;
	}
	public String getSubject() {
		return subject;
	}
	public void setSubject(String subject) {
		this.subject = subject;
	}
	public String getAppellation() {
		return appellation;
	}
	public void setAppellation(String appellation) {
		this.appellation = appellation;
	}
	public String getContext() {
		return context;
	}
	public void setContext(String context) {
		this.context = context;
	}
	public String getTail() {
		return tail;
	}
	public void setTail(String tail) {
		this.tail = tail;
	}
	<strong>@Override
	public  Mail clone() {
		// TODO Auto-generated method stub
		Mail mail = null;
		try {
			mail = (Mail)super.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return mail;
	}</strong>
	
	

}
我们看粗体部分,是实现了接口覆写的方法,下面我们看一下场景类的变化:

package demo;

import java.util.Random;
import java.util.concurrent.ForkJoinPool.ManagedBlocker;

import org.omg.CORBA.PUBLIC_MEMBER;

public class Client {
	
	
	
	private static int MAX_COUNT = 6;
	public static void main(String[] args){
		int i = 0;
		Mail mail = new Mail(new AdvTemplate());
		mail.setTail("xx银行版权所有");
		while(i<MAX_COUNT){
			Mail cloneMail = mail.clone();
			cloneMail.setAppellation(getRandString(5)+"先生");
			cloneMail.setReceiver(getRandString(5) + "@" + getRandString(8) + ".com");
			sendMail(cloneMail);
			i++;
		}
	
	}
	public static void sendMail(Mail mail){
		System.out.println("标题" +mail.getSubject() +"\t收件人" + mail.getReceiver() + "\t……发送成功!");
	}
	public static String getRandString(int maxLength){
		
		String source = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
		StringBuffer buffer = new StringBuffer();
		Random random = new Random();
		for(int i = 0;i<maxLength;i++){
			buffer.append(source.charAt(random.nextInt(source.length())));
			
		}
		return buffer.toString();
		
	}

}


运行结果保持不变,一样可以发送邮件,而且sendMail方法即使是使用了多线程也没有关系,注意看Client类中的mail.clone()这个方法,把对象复制一份,产生一个新的对象,和原有的对象一样,然后再修改细节的数据。这种不通过new关键字来产生一个对象,而是通过对象复制来实现的模式就叫做原型模式。

那么原型模式的优点是什么呢?

一性能优良

原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。

二逃避构造函数的约束

这即是它的优点也是它的缺点,直接在内存中拷贝,构造函数是不会执行的。优点是减少了约束,缺点是减少了约束,这个需要大家在实际应用时考虑。

原型模式使用场景:

资源优化场景······类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。

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

一个对象多个修改者的场景······一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。

在实际项目中,原型模式很少单独出现,一般是和工厂模式一起出现,通过clone方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与java融为一体。可以随时拿来使用。

原型模式使用注意事项:

原型模式虽然简单,但是在java中使用原型模式也就是clone方法还是有一些使用事项的,下面我们通过几个例子来看一下:

·················································································································································································································································

~~~构造函数不会被执行

一个实现Cloneable并重写了clone方法的类A,有一个无参构造或有参构造B,通过new关键字产生一个对象S,再然后通过S.clone()产生一个新的对象T,那么在对象拷贝时构造函数B是不会执行的。我们来看一下小demo:

可拷贝对象:

package demo;

public class Thing implements Cloneable{

	public Thing(){
		System.out.println("构造函数被执行了……");
	}
	@Override
	public Thing clone() {
		
		Thing thing = null;
		try {
			thing = (Thing)super.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return thing;
	}
}


看一下Client类:

package demo;

public class Client {
	public static void main(String[] args){
		//产生一个对象
		Thing thing = new Thing();
		//拷贝一个对象
		Thing cloneThing = thing.clone();
	}

}


运行结果:

构造函数被执行了……


对象拷贝时,构造方法确实没有执行,这点从原理上可以将的通,Object类的clone方法的原理就是从内存中(具体说是堆内存) 以二进制的方式进行拷贝,重新分配一个内存块,那构造函数没有被执行是非常正常的了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: