Prototype模式
应用场景
- 需要一个类的大量对象的时候,使用原型模式是最佳选择,因为原型模式是在内存中对这个对象进行拷贝,要比直接new这个对象性能要好很多,在这种情况下,需要的对象越多,原型模式体现出的优点越明显。
- 如果一个对象的初始化需要很多其他对象的数据准备或其他资源的繁琐计算,那么可以使用原型模式。
- 当需要一个对象的大量公共信息,少量字段进行个性化设置的时候,也可以使用原型模式拷贝出现有对象的副本进行加工处理。
本质
- 克隆生成对象
优点
- 由于clone方法是由虚拟机直接复制内存块执行,所以在速度上比使用new的方式创建对象要快。
- 可以基于原型,快速的创建一个对象,而无需知道创建的细节。
- 可以在运行时动态的获取对象的类型以及状态,从而创建一个对象。
缺点
- 配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
- 实现原型模式每个派生类都必须实现 Clone接口。
- 逃避构造函数的约束。
角色
-
客户(Client) 角色:
客户类提出创建对象的请求。 -
抽象原型(Prototype)角色:
这是一个抽象角色,通常接口或抽象类实现。在Java中,抽象原型角色通常实现了Cloneable接口。 -
具体原型(Concrete Prototype)角色:
被复制的对象。此角色需要实现抽象原型角色所要求的接口。
Prototype模式的类图
示例程序
示例程序的类图
示例代码
public class Product implements Cloneable {
private int ID;
private String name;
public Product() {
super();
}
public Product(int iD, String name) {
super();
ID = iD;
this.name = name;
}
public int getID() {
return ID;
}
public void setID(int iD) {
ID = iD;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return " ID:"+ID+" Name:"+name;
}
}
public class Order implements Cloneable {
private int num;
private String name;
private Product product;
public Order() {
super();
}
public Order(int num, String name, Product product) {
super();
this.num = num;
this.name = name;
this.product = product;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "订单数目:"+num+" 订单类型:"+name+product.toString();
}
}
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
int MAX=1000;
List<Order> list = new ArrayList<Order>();
Product product = new Product(1, "产品1");
Order order = new Order(2001,"公司订单",product);
int rest=order.getNum();
while (rest>MAX) {
Order temp = (Order) order.clone();
temp.setNum(MAX);
list.add(temp);
rest=order.getNum()-MAX;
order.setNum(rest);
}
list.add(order);
System.out.println("共有"+list.size()+"份订单");
for (int i=0; i<list.size(); i++) {
System.out.println(list.get(i).toString());
}
}
}
拓展思路
- 通过clone()来生成实例,而不是用new
相关设计模式
- Flyweight 模式
使用Potoype模式可以生成个与当前实例的状态完全相同的实例。
而使用Flyweight模式可以在不同的地方使用同个实例。 - Memento模式
使用Prototype模式可以生成一个与当前实例的状态完全相同的实例。
而使用Mermento模式可以保存当前实例的状态,以实现快照和撤销功能。 - Composite模式以及Decorator模式
经常使用Composite模式和Decorator模式时,需要能够动态地创建复杂结构的实例。这时可
以使用Prototype模式,以帮助我们方便地生成实例。 - Command模式
想要复制Command模式中出现的命令时,可以使用Prototype模式。
满足的原则
- 依赖倒转原则