1、背景
public class Client {//发送邮件的数量private static int MAX_COUNT = 3;public static void main(String[] args) {int i = 0;//定义模板Mail mail = new Mail(new AdvTemplate());//模拟发送场景while (i < MAX_COUNT) {mail.setApplication(getRandomString(5) + " 先生(女士) ");mail.setReceiver(getRandomString(5) + "@" + getRandomString(8) + ".com");sendMail(mail);i++;}}//发送邮件public static void sendMail(Mail mail) {System.out.println("标题:" + mail.getSubject() + "\t收件人:" + mail.getReceiver() + "\t...发送成功!");}//获得指定长度的随机字符串public static String getRandomString(int maxLength) {String source = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";StringBuffer sb = new StringBuffer();Random random = new Random();for (int i = 0; i < maxLength; i++) {sb.append(source.charAt(random.nextInt(source.length())));}return sb.toString();}}
看到实现结果,长舒了一口气,终于实现了。可是,仔细观察一下我们的设计,会发现存在很大的问题:程序是单线程的,批量发送耗时太长,假如每天要给600万用户发送邮件,按照一封0.02秒计算,需要33小时。。。
2、Prototype的优点
性能优良:原型模式是在内存中拷贝二进制流,要比直接new一个对象好得多,特别是在一个循环体内产生大量对 象时,原型模式能更好的体现其优点。
逃避构造函数的约束:直接在内存中拷贝,不会执行构造函数,减少了约束
Prototype的使用场景
资源优化场景:类初始化需要消耗非常多的资源,所以在需要使用大量同一对象的时候可以考虑原型模式
性能和安全要求的场景:通过new产生一个对象要非常繁琐的数据准备或访问权限,可以使用原型模式替代
一个对象多个修改者场景:一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改该对象的值,可以 使用原型模式拷贝多个对象供调用者使用
3、深浅拷贝的代码
package com.aliyun.sales.lead.service.action.impl;class Address /*implements Cloneable*/{private String country;private String province;private String city;public String getCountry() {return country;}public void setCountry(String country) {this.country = country;}public String getProvince() {return province;}public void setProvince(String province) {this.province = province;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}@Overridepublic String toString() {return "Address [country=" + country + ", province=" + province+ ", city=" + city + "]";}public Address(String country, String province, String city) {super();this.country = country;this.province = province;this.city = city;}/* @Overridepublic Address clone() throws CloneNotSupportedException {return (Address) super.clone();}*/}
package com.aliyun.sales.lead.service.action.impl;class Customer implements Cloneable{public int ID;public int age;public Address address;public int getID() {return ID;}public void setID(int iD) {ID = iD;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Address getAddress() {return address;}public void setAddress(Address address) {this.address = address;}public Customer(int iD, int age, Address address) {super();ID = iD;this.age = age;this.address = address;}@Overridepublic String toString() {return "Customer [ID=" + ID + ", age=" + age + ", address=" + address+ "]";}@Overridepublic Customer clone() throws CloneNotSupportedException {Customer customer = (Customer) super.clone();/*customer.address = address.clone();*/return customer;}public static void main(String[] args) throws CloneNotSupportedException {Address address = new Address("CH" , "SD" , "QD");Customer customer1 = new Customer(1 , 23 , address);Customer customer2 = customer1.clone();customer2.getAddress().setCity("JN");customer2.setID(2);System.out.println("customer1:"+customer1.toString());System.out.println("customer2:"+customer2.toString());}}
实现一个Clonable接口,就是一个需要标识;
重写Object的clone方法;
4、深浅拷贝的区别
深浅拷贝都是针对引用类型的属性来说的,应为基本类型的名和值都存放在栈中,clone的时候名和值都克隆一份到栈中,如果是引用类型,引用类型属性的值存放在堆中,名字存放到栈中,但是在栈中存放了堆中值的地址,浅拷贝就是在栈中拷贝一份名字和堆中值得地址,而深拷贝是将堆中值得在堆中开辟一块内存拷贝一份新的,栈中的名称对应值的引用是新开辟的那块内存的地址。
参考https://blog.csdn.net/weixin_41910848/article/details/82144671
