原形模式(PrototypePattern, 创建型模式,创建重复对象且保证性能, 对象的克隆)
通常使用原型模式创建一个原型接口, 用于获取创建对象的克隆, 对于浅拷贝与深拷贝不用纠结, 他们二者的区别就在于重写Clonable的clone方法
浅拷贝与深拷贝
浅拷贝: 直接调用Object的clone
public Object clone() {
Object clone=null;
try {
clone=super.clone(); //不用管Object内部元素的情况直接调用Object的clone方法
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
深拷贝: 对clone对象( 此对象内部具有数组/集合/map等复合数据 )内部的数据再进行一次克隆
此处假设clone对象内部有一个ArrayList数组, ArrayList中存储A对象
public Object clone() {
Object clone=null;
try {
clone=super.clone();
clone.getArray() = new ArrayList<A>(array.size()); //先将内部的ArrayList克隆出来
for (int i=0; i < array.size(); i++){// 然后对ArrayList中的数据进行逐一克隆
//从数组中获取每个元素, 然后进行克隆, 此处A对象内部没有复合数据, 最后将clone好的数据存入clone的array中
clone.getArray().add( (A)array.get(i).clone() );
}
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
因为只是调用Object的clone无法对克隆对象内部的数组类型进行复制, 所以还要针对拷贝对象的内部的数组再一次
操作流程
- 使用方式
原型模式通过拷贝一个现有对象生成新对象.
浅拷贝实现Clonable接口, 重写clone方.
深拷贝与浅拷贝一致, 也可以通过实现Serializable读取二进制流
1.利用序列化产生的对象是对原对象的复制
2.将对象序列化存入缓冲区, 然后将缓冲区对象读出, 用clone的引用指向该对象
- 角色定义
原型角色:定义用于复制现有的实例来生成新的实例的方法(实现Cloneable接口的类)
具体原型角色:实现用于复制现有实例来生成新实例的方法(具有clone()方法的类)
使用者角色:维护一个注册表, 提供获取clone的类
- 使用场景
1.资源优化, 类加载需要消耗很多资源, 性能和安全要求高的场景
2.通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模型
3.一个对象,多个修改者
4.大多数原型模式伴随工厂模式出现,通过clone方法创建一个对象,然后由工厂方法提供给调用者
-
优点
性能提高,逃避构造函数的约束, 不推荐使用序列化处理clone -
缺点
配备克隆操作需要对类的功能全盘考虑,对已有的类不一定很容易,特别是当一个类饮用不支持串行化的间接对象,或者引用含有循环结构(对象出现多层次的引用); 必须实现Cloneable接口
代码演示:
利用克隆, 事先将一些构造需要高代价的对象放入缓冲区, 然后在下次需要新的对象的时候直接去缓冲区拿( 缓冲区利用clone的方式给新对象, 而不是通过构造函数 )
package com.PrototypePattern;
import java.util.Hashtable;
public class ShapePrototypePattern {
public static void main(String[] args) {
//设计一个圆形的缓冲区
Shape shape = new Circle();
shape.setId("1");
ShapeCache.loadCache(shape);
//使用对应的图形缓冲区获得克隆对象clone, clone1, clone2
Shape clonedShape=ShapeCache.getShape("1");
System.out.println("Shape: "+clonedShape.hashCode());
Shape clonedShape1=ShapeCache.getShape("1");
System.out.println("Shape: "+clonedShape1.hashCode());
Shape clonedShape2=ShapeCache.getShape("1");
System.out.println("Shape: "+clonedShape2.hashCode());
}
}
//针对不同的图形设计不同的缓冲区模块克隆模块
class ShapeCache{
private static Hashtable<String,Shape>shapeMap=new Hashtable<String,Shape>();
//使用get方法获得的图形都是原图形的克隆对象
public static Shape getShape(String id) {
Shape cachedShape=shapeMap.get(id);
return (Shape)cachedShape.clone();
}
//将new出的对象放入Hashtable, 获得相应的图形直接获取clone
public static void loadCache(Shape shape) {
shapeMap.put(shape.getId(), shape);
}
}
//原型角色,实现Cloneable接口,调用Object的clone方法
//当具体实现类需要clone的时候就可以直接调用clone
abstract class Shape implements Cloneable{
private String id;
protected String type;
abstract public void draw();
public String getType() {
return type;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id=id;
}
public Object clone() {
Object clone=null;
try {
clone=super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
class Circle extends Shape{
public Circle() {
type="Circle";
}
@Override
public void draw() {
System.out.println("Circle");
}
}
class Rectangle extends Shape{
public Rectangle() {
type="Rectangle";
}
@Override
public void draw() {
System.out.println("Rectangle");
}
}
class Square extends Shape{
public Square() {
type="Square";
}
@Override
public void draw() {
System.out.println("Square");
}
}
结语:
原型模式就是clone, 用于提高性能, 避免构造对象的时候加大资源的开销