1、原型模式的定义
原型模式:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
原型模式的核心是一个clone方法,被拷贝对象需要实现cloneable接口并重写clone()方法。
2、代码示例
/** * 广告信模板代码 * */ public class AdvTemplate { //广告信名称 private String advSubject = "XX银行国庆信用卡抽奖活动"; //广告信内容 private String advContext = "国庆抽奖活动通知: 只要刷卡就送你一百万! ..."; //取得广告信的名称 public String getAdvSubject(){ return this.advSubject; } //取得广告信的内容 public String getAdvContext(){ return this.advContext; } }
/** * 邮件类代码 * */ public class Mail implements Cloneable { //收件人 private String receiver; //邮件名称 private String subject; //称谓 private String appellation; //邮件内容 private String contxt; //邮件的尾部, 一般都是加上"XXX版权所有"等信息 private String tail; //构造函数 public Mail(AdvTemplate advTemplate){ this.contxt = advTemplate.getAdvContext(); this.subject = advTemplate.getAdvSubject(); } @Override protected Mail clone() { Mail mail = null; try { mail = (Mail) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return mail; } 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 getContxt() { return contxt; } public void setContxt(String contxt) { this.contxt = contxt; } public String getTail() { return tail; } public void setTail(String tail) { this.tail = tail; } }
/** * 场景类 * */ 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.setAppellation(getRandString(5) + " 先生( 女士) "); mail.setReceiver(getRandString(5) + "@" + getRandString(8) + ".com");*/ 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() + " 收件人:" + mail.getReceiver() + " ...发送成功! "); } //获得指定长度的随机字符串 public static String getRandString(int maxLength){ String source ="abcdefghijklmnopqrskuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; StringBuffer sb = new StringBuffer(); Random rand = new Random(); for(int i = 0; i < maxLength; i++){ sb.append(source.charAt(rand.nextInt(source.length()))); } return sb.toString(); } }
3、原型模式优点
性能优良
原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。
逃避构造函数的约束
这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的。优点就是减少了约束,缺点也是减少了约束,需要大家在实际应用时考虑。
4、原型模式的使用场景
资源优化场景
类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
性能和安全要求的场景
通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
一个对象多个修改者的场景
一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。
5、原型模式的注意事项
构造函数不会被执行
执行clone()方法时,原型对象的构造函数不会被执行。
浅拷贝和深拷贝
浅拷贝:clone()方法只拷贝对象本身,对象内部的数组、引用对象等都不拷贝(基本类型和string类型会被拷贝),还是指向原生对象的内部元素地址。
深拷贝:原生对象所有内容全拷贝,互不影响。
clone与final两个冤家
要使用clone方法, 类的成员变量上不要增加final关键字。