原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式是实现了一个原型接口(java.lang.Cloneable),该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
原型模式组成
原型(Prototype):实际对象的原型(Movie、Album、Show);
原型注册缓存(Prototype Registry):用于内存中缓存具体的原型对象(PrototypeFactory#protoTypes);
客户端:负责从注册表中获取原型对象。
案例实践
自定义一个接口类型,继承Cloneable接口,作为原型模式的接口类型。
package com.iblog.pattern.prototype;
/**
* ProtoType pattern interface declaration.
*/
public interface ProtoTypeCapable extends Cloneable {
ProtoTypeCapable clone() throws CloneNotSupportedException;
}
假设Movie、Album、Show对象的创建非常复杂,我们通过原型模式来覆盖其对象创建。
package com.iblog.pattern.prototype;
public class Movie implements ProtoTypeCapable {
private String name;
public ProtoTypeCapable clone() throws CloneNotSupportedException {
// clone a Movie object in this.
return (Movie) super.clone();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "movie => [name:" + name + "]";
}
}
package com.iblog.pattern.prototype;
public class Album implements ProtoTypeCapable {
private String name;
@Override
public ProtoTypeCapable clone() throws CloneNotSupportedException {
return (Album) super.clone();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "album => [name:" + name + "]";
}
}
package com.iblog.pattern.prototype;
public class Show implements ProtoTypeCapable {
private String name;
@Override
public ProtoTypeCapable clone() throws CloneNotSupportedException {
return (Show) super.clone();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Show => [name:" + name + "]";
}
}
在案例中,我们将原型对象注册地址与原型客户端都封装在一个工厂操作类中。
package com.iblog.pattern.prototype;
import java.util.HashMap;
import java.util.Map;
public class ProtoTypeFactory {
public static class ModelType {
public static final String MOVIE = "Movie";
public static final String ALBUM = "Album";
public static final String SHOW = "Show";
}
private static Map<String, ProtoTypeCapable> protoTypes = new HashMap<>();
static {
protoTypes.put(ModelType.MOVIE, new Movie());
protoTypes.put(ModelType.ALBUM, new Album());
protoTypes.put(ModelType.SHOW, new Show());
}
public static ProtoTypeCapable getInstance(final String type) throws CloneNotSupportedException {
return protoTypes.get(type).clone();
}
}
这样在Java中可以通过在ProtoTypeFactory#getInstance(type)方法很方便克隆一个目标对象。
总结
原型模式属于创建型模式的一种,但是在我们实际应用中场景并不广泛,只有在对象创建十分复杂的情景中才考虑原型模式;此外需要注意原型模式在克隆对象时候对于其中的属性字段的拷贝。
github: pattern-example