一、原型模式的概念
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
二、什么时候使用原型模式
原型模式可以理解为:以一个类作为模板,克隆出无数个类,克隆出来的类与模板就再无关联。
以下场景可以使用原型模式:
- 构造函数较复杂,或者不想使用构造函数创建对象;
- 资源优化,在初始化时一个类时需要较多的资源,使用原型模式,初始化一次后,就进行克隆(不会再初始化);
- 性能提升,使用克隆要比使用new创建一个对象的性能高,克隆直接在内存中操作二进制流,new则需要JVM做很多的准备(加载、验证、准备、解析、初始化),所以在某些场景要大量创建相同对象时,可以节约性能;
下面就以提升性能作为场景,来用Java实现原型模式。
三、怎么使用原型模式
3.1 实现方式
首先假设一个场景,中秋节将至,系统要为全部的500万(或者更多)用户发送消息(一条条发,先不考虑其他技术实现,主要为了说明原型模式)。这种情况下,如果贸然使用for循环来通过new关键字创建500万个对象,假设new一个对象要花费0.04秒,那么new500万个也未必能在一天之内发送完毕。
这种情况下就可以使用原型模式来提升性能,下面看类图和代码:
代码如下:
// 消息模板,继承Cloneable接口
public interface MessageTemplate extends Cloneable {
// 克隆消息
MessageTemplate cloneMessage() throws CloneNotSupportedException;
}
// 消息
public class Message implements MessageTemplate {
// 实现克隆方法
public Message cloneMessage() throws CloneNotSupportedException {
Message message;
message = (Message) clone();
return message;
}
@Override
public String toString() {
return "Message{" +
"createTime=" + createTime +
", title='" + title + '\'' +
", context='" + context + '\'' +
", phone='" + phone + '\'' +
'}';
}
// getter and setter ...
private Date createTime;
private String title;
private String context;
private String phone;
}
// 使用克隆模式
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
// 模拟发送消息,加入发送100万个消息给不同用户
// 消息模板使用相同模板,消息内容有某些不同
// 则可以使用原型模式
int count = 100; // 用户数量,就不写100万了
// 创建模板
Message message = new Message();
message.setTitle("节日关怀");
message.setContext("尊敬的%s,您好。吧啦吧啦……");
for (int i = 0; i < count; i++) {
Message m = message.cloneMessage();
m.setContext(String.format(message.getContext(), i));
m.setPhone(i + "");
m.setCreateTime(new Date());
System.out.println(m.toString());
}
}
}
// 输出
Message{createTime=Tue May 19 23:05:52 CST 2020, title='节日关怀', context='尊敬的0,您好。吧啦吧啦……', phone='0'}
Message{createTime=Tue May 19 23:05:52 CST 2020, title='节日关怀', context='尊敬的1,您好。吧啦吧啦……', phone='1'}
Message{createTime=Tue May 19 23:05:52 CST 2020, title='节日关怀', context='尊敬的2,您好。吧啦吧啦……', phone='2'}
......
Message{createTime=Tue May 19 23:05:52 CST 2020, title='节日关怀', context='尊敬的98,您好。吧啦吧啦……', phone='98'}
Message{createTime=Tue May 19 23:05:52 CST 2020, title='节日关怀', context='尊敬的99,您好。吧啦吧啦……', phone='99'}
上面的代码就是原型模式的做法和用法。
核心就是使用了Java中Object对象自带的clone方法,来完成类的克隆。
这里需要注意的是Cloneable接口,它比较特别,clone方法并不是它定义的,它只是用来描述对象可以使用clone方法,是一种标记接口。
3.2 原型模式的好处
原型模式的好处,就体现他的使用场景:
- 构造函数较复杂,或者不想使用构造函数创建对象;
- 资源优化,在初始化时一个类时需要较多的资源;
- 性能提升,使用克隆要比使用new创建一个对象的性能高;
3.3 注意事项
原型模式的注意事项,主要强调两点:
忽略构造函数:使用clone()方法,不会触发对象的构造函数,如果类需要在构造函数中进行一些业务,则需要注意;
深拷贝:clone()方法会复制基本类型,但是引用类型复制的是引用的内存地址(指针),所以带有引用类型的对象进行clone()时,需要处理深拷贝,网上有很多文章,就不在此叙述了;
四、总结
总的来说,原型模式属于比较简单的设计模式之一,也比较好理解,主要理清2点就能比较好的应用它:
使用场景:在什么时候适合用原型模式来创建对象;
技术实现:涉及到了使用cloneable接口,使用Object对象的clone方法,以及注意深拷贝;
以上就是我对原型模式的一些理解,有不足之处请大家指出,谢谢。
来源:oschina
链接:https://my.oschina.net/u/2450666/blog/4284517