定义与类型
- 定义:指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
- 不需要知道创建的细节,不调用构造函数
- 类型:创建型
适用场景
- 类初始化消耗较多资源
- new产生的一个对象需要非常繁琐的过程(数据准备、访问权限等)
- 构造函数比较复杂
- 循环体中产生大量对象时
优点
- 原型模式性能比new一个对象要高
- 简化创建过程
缺点
- 必须具备克隆方法
- 对克隆复杂对象或对克隆出的对象进行复杂改造时,容易引入风险
- 深拷贝、浅拷贝要运用得当
原型的扩展
- 深克隆
- 浅克隆
看下面代码:
package design.prototype;
public class Mail {
private String name;
private String emailAddress;
private String content;
public Mail() {
System.out.println("Mail class Constructor");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "Mail{" +
"name='" + name + '\'' +
", emailAddress='" + emailAddress + '\'' +
", content='" + content + '\'' +
'}';
}
}
package design.prototype;
import java.text.MessageFormat;
public class MailUtil {
public static void sendMail(Mail mail){
String outputContent = "向 {0} 同学,邮件地址:{1}," +
"邮件内容:{2}.发送邮件成功";
System.out.println(MessageFormat.format(outputContent, mail.getName(),mail.getEmailAddress(), mail.getContent()));
}
public static void saveOriginMailRecod(Mail mail){
System.out.println("存储originMain记录,originMain:"+mail.getContent());
}
}
package design.prototype;
public class Test {
public static void main(String[] args) {
Mail mail = new Mail();
mail.setContent("初始化模板");
for(int i=0;i<10;i++){
mail.setName("姓名"+i);
mail.setContent("恭喜您,中奖了");
mail.setEmailAddress("姓名"+i+"@qq.com");
MailUtil.sendMail(mail);
}
MailUtil.saveOriginMailRecod(mail);
}
}
假设new Mail方法非常复杂,并且在循环中产生大量的对象,那就可以用克隆来实现。
package design.prototype;
public class Mail implements Cloneable{
private String name;
private String emailAddress;
private String content;
public Mail() {
System.out.println("Mail class Constructor");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "Mail{" +
"name='" + name + '\'' +
", emailAddress='" + emailAddress + '\'' +
", content='" + content + '\'' +
'}'+super.toString();
}
@Override
protected Object clone() throws CloneNotSupportedException {
System.out.println("clone mail object");
return super.clone();
}
}
package design.prototype;
import java.text.MessageFormat;
public class MailUtil {
public static void sendMail(Mail mail){
String outputContent = "向 {0} 同学,邮件地址:{1}," +
"邮件内容:{2}.发送邮件成功";
System.out.println(MessageFormat.format(outputContent, mail.getName(),mail.getEmailAddress(), mail.getContent()));
}
public static void saveOriginMailRecod(Mail mail){
System.out.println("存储originMain记录,originMain:"+mail.getContent());
}
}
package design.prototype;
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Mail mail = new Mail();
mail.setContent("初始化模板");
System.out.println("初始化"+"mail:"+mail);
for(int i=0;i<10;i++){
Mail mailTemp = (Mail) mail.clone();
mailTemp.setName("姓名"+i);
mailTemp.setContent("恭喜您,中奖了");
mailTemp.setEmailAddress("姓名"+i+"@qq.com");
MailUtil.sendMail(mailTemp);
System.out.println("mailTemp"+mailTemp);
}
MailUtil.saveOriginMailRecod(mail);
}
}
再来看一个例子:
package design.prototype.clone;
import java.util.Date;
public class pig implements Cloneable{
private String name;
private Date birthday;
public pig(String name, Date birthday) {
this.name = name;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "pig{" +
"name='" + name + '\'' +
", birthday=" + birthday +
'}'+super.toString();
}
}
package design.prototype.clone;
import java.util.Date;
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Date birthday = new Date(0L);
pig pig = new pig("佩奇",birthday);
pig pig1 = (design.prototype.clone.pig) pig.clone();
System.out.println(pig);
System.out.println(pig1);
pig.getBirthday().setTime(6666666666L);
System.out.println(pig);
System.out.println(pig1);
}
}
只改了pig的生日,pig1的生日也变了。
这个birthday引用的是同一个对象,改其中一个另一个也会改变,这个是浅克隆,如果要深克隆的话要怎么做呢?其实很简答,只需要在克隆方法中这样写:
再运行一下:
这下就对了。
克隆破坏单例
package design.singleton;
import java.io.Serializable;
public class HungrySingleton implements Serializable,Cloneable{
private final static HungrySingleton hungrySingleton;
static {
hungrySingleton = new HungrySingleton();
}
private HungrySingleton(){
if (hungrySingleton != null){
throw new RuntimeException("单例构造器禁止使用反射");
}
}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
private Object readResolve(){
return hungrySingleton;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
package design.prototype.clone;
import design.singleton.HungrySingleton;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
public class Test {
public static void main(String[] args) throws CloneNotSupportedException, InvocationTargetException, IllegalAccessException, NoSuchMethodException {
HungrySingleton hungrySingleton = HungrySingleton.getInstance();
Method method = hungrySingleton.getClass().getDeclaredMethod("clone");
method.setAccessible(true);
HungrySingleton cloneHungrySingleton = (HungrySingleton) method.invoke(hungrySingleton);
System.out.println(hungrySingleton);
System.out.println(cloneHungrySingleton);
}
}
破坏了单例模式,怎么解决呢?可以让单例类不实现cloneable接口,还有就是看下面代码:
@Override
protected Object clone() throws CloneNotSupportedException {
return getInstance();
}
在重载方法中改成上面的。