原形模式(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, clone2Shape 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, 获得相应的图形直接获取clonepublic 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";}@Overridepublic void draw() {System.out.println("Circle");}
}
class Rectangle extends Shape{public Rectangle() {type="Rectangle";}@Overridepublic void draw() {System.out.println("Rectangle");}
}
class Square extends Shape{public Square() {type="Square";}@Overridepublic void draw() {System.out.println("Square");}
}
结语:
原型模式就是clone, 用于提高性能, 避免构造对象的时候加大资源的开销