一、定义
用原型实例指定创建对象种类,并且通过拷贝这些原型创建新的对象。原型模式的核心是clone方法,通过该方法进行对象的拷贝,Java提供了一个Cloneable接口来标示这对象是可以拷贝的,为什么说是“标示”呢 ?JDK源码中Cloneable 接口是一个方法都没有,这个接口只是一个标记的作用,在jvm中具有这个标识才可能被拷贝,且类中必须要重新clone()方法,覆写了Object类中的clone方法。
二、代码演示
通过一个部门给不同的人员发相同内容的邮件为例,邮件里面不同的是收件人地址,其它都是一样的,通过clone产生公用属性一直,特性不一致的的mail。
2.1 邮件类
public class Mail implements Cloneable {
//收件人
private String receiver ;
//邮件名称
private String subject ;
//称谓
private String appellation ;
//邮件内容
private String context;
//邮件签名
private String tail ;
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;
}
@Override
public Mail clone(){
Mail mail = null ;
try{
mail = (Mail)super.clone();
}catch (Exception e){
e.printStackTrace();
}
return mail ;
}
@Override
public String toString(){
String result = "Mail{";
result = result + "receiver:"+receiver + "|";
result = result + "appellation:"+appellation + "|";
result = result + "context:"+context + "|";
result = result + "}";
return result;
}
}
2.2 应用场景类
public class Client {
public static void main(String args[]){
Mail mails = new Mail();
mails.setContext("xx部门通告邮件");
mails.setAppellation("admin");
//下面发送给不同的收件人
Mail mailNew1 = mails.clone();
mailNew1.setReceiver("[email protected]");
System.out.println(mailNew1.toString());
System.out.println("---------------------------------");
Mail mailNew2 = mails.clone();
mailNew2.setReceiver("[email protected]");
System.out.println(mailNew2.toString());
}
}
结果:
Mail{receiver:[email protected]|appellation:admin|context:xx部门通告邮件|}
---------------------------------
Mail{receiver:[email protected]|appellation:admin|context:xx部门通告邮件|}
三、优点
3.1 性能优良
原型模式是在内存中通过二进制流的拷贝,要比直接new一个对象性能要好,特别是要在一个循环体内产生大量的对象是,原型模式可以更好的体现其优点。
3.2 逃避构造函数约束
这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的。有点事减少了约束,缺点是需要大家在实际应用中考虑。
四、缺点
4.1 可能有线程安全问题
在多线程环境下,多个线程公用一个对象本身是有线程安全隐患的, 这在实际项目中,需要着重考虑。
五、应用场景
5.1 优化资源场景
类初始化需要消化非常多的资源,这个资源包括数、硬件。
5.2 性能和安全要求的场景
通过new一个对象需要频繁的准备数据或访问权限,则可以通过使用原型模式。
5.3 一个对象多个修改者场景
一个对象需要提供给其它的对象访问,而且各个调用者可能都需要修改其值,可以用原型模式。
在实际项目中,原型模式单独使用的很少,一般是和工厂模式一起出现,通过clone的方法创建一个对象,然后由工程方法提供给调用者。
六、注意事项
6.1 原型模式必备两要素
A、实现Cloneable接口;B、重写Object类clone方法;
6.2 构造函数不会被执行
6.3 注意浅拷贝和深拷贝的区别
使用原型模式的时候,有一些类中的成员变量可能不会被拷贝。应用的成员变量必须满足两个条件才不会被拷贝。一是 类的成员变量,而不是方法内变量;二是必须是一个可变的引用对象,而不是一个不可变对象或原始类型。