23种设计模式之原型模式(二)
2015-06-18 09:52
225 查看
我们接着上面的接着研究:
是把sendMail()修改成多线程的问题,但是改成多线程还是有问题呀,产生第一封邮件对象,放到线程一中运行,还没有发送出去;线程二也启动了,直接就把对象mail的收件人地址称谓全都改掉了,线程就不安全了。说道这里,你会说这有n种方式去解决,其中一种就是使用一种新型模式来解决这个问题:通过对象的复制功能来解决这个问题。
我们只需要给Mail类增加一个Cloneable接口(java自带的接口),Mail实现了这个接口后,在Mail类中覆写了clone方法,我们来看Mail类的改变:
运行结果保持不变,一样可以发送邮件,而且sendMail方法即使是使用了多线程也没有关系,注意看Client类中的mail.clone()这个方法,把对象复制一份,产生一个新的对象,和原有的对象一样,然后再修改细节的数据。这种不通过new关键字来产生一个对象,而是通过对象复制来实现的模式就叫做原型模式。
那么原型模式的优点是什么呢?
一性能优良
原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。
二逃避构造函数的约束
这即是它的优点也是它的缺点,直接在内存中拷贝,构造函数是不会执行的。优点是减少了约束,缺点是减少了约束,这个需要大家在实际应用时考虑。
原型模式使用场景:
资源优化场景······类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
性能和安全要求的场景······通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
一个对象多个修改者的场景······一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
在实际项目中,原型模式很少单独出现,一般是和工厂模式一起出现,通过clone方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与java融为一体。可以随时拿来使用。
原型模式使用注意事项:
原型模式虽然简单,但是在java中使用原型模式也就是clone方法还是有一些使用事项的,下面我们通过几个例子来看一下:
·················································································································································································································································
~~~构造函数不会被执行
一个实现Cloneable并重写了clone方法的类A,有一个无参构造或有参构造B,通过new关键字产生一个对象S,再然后通过S.clone()产生一个新的对象T,那么在对象拷贝时构造函数B是不会执行的。我们来看一下小demo:
可拷贝对象:
看一下Client类:
运行结果:
对象拷贝时,构造方法确实没有执行,这点从原理上可以将的通,Object类的clone方法的原理就是从内存中(具体说是堆内存) 以二进制的方式进行拷贝,重新分配一个内存块,那构造函数没有被执行是非常正常的了。
是把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方法的原理就是从内存中(具体说是堆内存) 以二进制的方式进行拷贝,重新分配一个内存块,那构造函数没有被执行是非常正常的了。
相关文章推荐
- 移动端meta标签的设置
- 关于 HDC 的释放
- sublime_text 2.0.2 绑定cocos2dx lua 开发游戏
- JAVA实现FTP断点上传的方法
- 嵌入式C语言编程规范(个人规约)
- 嵌入式C语言编程规范(个人规约)
- 项目杂记二
- JAVA如何判断字符串编码
- 嵌入式C语言编程规范(个人规约) 分类: 嵌入式开发学习 2015-06-18 09:51 37人阅读 评论(0) 收藏
- sprintf() 处理 float类型的数字,保留小数位等。
- 缓存机制
- CAS实战の获取多用户信息
- redis 对数组的操作
- 递归例子(Javascript)
- 公用表表达式(CTE)
- pthread_create会导致内存泄露
- 乐视TV2015校园招聘A第二个大的发行量(of中国Academy科学大学站)
- 编译:ffmpeg,精简ffmpeg.exe
- 插件二之页面加载进度条pace.js
- 使用FFmpeg将mp4转为ts(代码实现)