原型模式(Prototype Pattern)是一种创建模式(Creational Design Patterns)。原型模式用于简化创建对象的过程。在面向对象程序设计中,开发人员可以使用构造函数(Constructor),工厂模式(Factory Pattern)、抽象工厂模式(Abstract Factory Pattern)和建造者模式(Builder Pattern)来创建对象。但是,与之不同的是,原型模式能够帮助开发人员快速创建大量的、内容相同的对象。
在大型项目中,有时创建对象是很昂贵的。例如,可能需要在数据库中查询关键数据,或者从远程服务器中获取相关文件。如果反复执行这些操作,会给系统造成额外的负担。因此,开发人员可以利用原型模式,将这些关键数据存放在原型对象中。在构建新的对象时,可以直接从原型对象中获取。在原型模型下,开发人员可根据业务需求决定使用浅复制(Shallow Copy)或者深度复制(Deep Copy)来创建新的对象。点击这里查看浅复制和深度复制的区别。
在原型模式中,有五个参与方。
图一 原型模式结构。
在本例中,我们将使用产品发布消息对象(Release Message)为例,来解释原型模式的使用方法。AbstractReleaseMessage表达的是一条产品发布消息。当有新版本发布时,开发人员往往会在产品说明手册中附上一条消息,说明新产品的名称、版本号和发布日期。所以,AbstractReleaseMessage类中包含了三个成员变量,分别是productName、version和releaseDate。
getReleaseStatement()方法用于创建一个与当前对象内容相同的新对象。getMessage()方法则生成相应的发布消息。
public abstract class AbstractReleaseMessage implements Cloneable {
private String productName = null;
private String version = null;
private String releaseDate = null;
public String getProductName() {
return productName;
}
public String getVersion() {
return version;
}
public String getReleaseDate() {
return releaseDate;
}
public abstract AbstractReleaseMessage getReleaseStatement();
public abstract String getMessage();
}
假设小水滴公司正好开发完成新的Web应用程序,亟待发布。那么,开发人员可能会创建一个新类,命名为WebApplicationReleaseMessage。它继承自AbstractReleaseMessage。在getReleaseStatement()方法中,因为WebApplicationReleaseMessage未定义任何成员变量,所以,它可以直接调用基类的clone()方法,复制出一个内容相同的对象。getMessage()方法则生成Web应用程序的发布消息。
public class WebApplicationReleaseMessage extends AbstractReleaseMessage {
public WebApplicationReleaseMessage(String version, String releaseDate) {
super("web application", version, releaseDate);
}
@Override
public AbstractReleaseMessage getReleaseStatement() {
try {
return (WebApplicationReleaseMessage)super.clone();
} catch (CloneNotSupportedException ex) {
System.err.println(ex.getMessage());
}
return null;
}
@Override
public String getMessage() {
return String.format("The web application (version %s) was released on %s", this.getVersion(), this.getReleaseDate());
}
}
上述的对象是由ReleaseMessageManager管理维护的。ReleaseMessageManager定义了管理AbstractReleaseMessage对象的接口。register()方法允许向管理器ReleaseMessageManager注册具体的AbstractReleaseMessage对象,而get()方法则返回对应的AbstractReleaseMessage对象。Prototype模式的运用就封装在get()方法的实现中。
public interface ReleaseMessageManager {
public void register(String label, AbstractReleaseMessage message);
public AbstractReleaseMessage get(String label);
}
ReleaseMessageManagerImpl是ReleaseMessageManager接口的一个实现。在内部,它使用一个Map对象prototypes来保存所有注册的AbstractReleaseMessage对象。每当register()方法被调用时,就会向prototypes成员变量中插入一个新的<Label, AbstractReleaseMessage>对。当get()方法被调用时,在对象存在的情况下,会调用clone()方法创建出一个新的对象,并将其返回。
public class ReleaseMessageManagerImpl implements ReleaseMessageManager {
private Map<String, AbstractReleaseMessage> prototypes = null;
public ReleaseMessageManager() {
prototypes = new HashMap<String, AbstractReleaseMessage>();
}
public void register(String label, AbstractReleaseMessage message) {
this.prototypes.put(label, message);
}
public AbstractReleaseMessage get(String label) {
AbstractReleaseMessage message = this.prototypes.get(label);
if (message != null) {
try {
return (AbstractReleaseMessage)message.clone();
} catch (CloneNotSupportedException ex) {
System.err.println(ex.getMessage());
}
}
return null;
}
}
因此,当使用ReleaseMessageManager创建对象时,开发人员需要首先创建出原型对象,并将其注册到ReleaseMessageManager中。在此之后,开发人员就能够快速的创建出大量的、内容相同的对象了。
public class PrototypeClient {
public static void main(String[] args) {
WebApplicationReleaseMessage message = new WebApplicationReleaseMessage("1.0", "2020-11-02");
ReleaseMessageManager messageManager = new ReleaseMessageManagerImpl();
messageManager.register("latest-webapp", message);
...
AbstractReleaseMessage releaseMessage = messageManager.get("latest-webapp");
if (releaseMessage != null) {
System.out.println(releaseMessage.getMessage());
}
}
}
原型模式虽然提供了快速、高效的创建大量对象的一种方法,但是,它的缺点也非常明显。在大型项目中,对象之间的关系往往较为复杂,正确使用和实现clone()方法的难度也非常大。而且,现代计算机的处理速度已非常快,对象创建过程往往并不是应用程序的性能瓶颈,因此,原型模式并没有其他创建模式那样应用广泛。
本章介绍了原型模式的结构和使用方法。原型模式并不复杂,它的主要优点是原型对象内部保存了一份创建对象所需的数据。当需要创建大量对象,并且创建过程比较昂贵的时候,直接从原型对象中获取这些关键信息,能够有效的提升系统的整体性能。
注册用户登陆后可留言