原型模式
用于创建重复的对象,同时保证性能。实现了一个原型接口,该接口用于创建当前对象的克隆,当直接创建对象的代价比较大的时候,则采用这种模式。即用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
解决了什么?
在运行期间建立和删除原型
什么时候使用?
- 当一个系统应该独立于它的产品创建,构成和表示时
- 当要实例化的类是在运行时刻指定时,例如动态装载
- 为了避免创建一个与产品类层次平行的工厂类层次时
- 当一个类的实例只能由几个不同状态组合中的一种时,建立相应数目的原型并克隆他们可能比每次用适合的状态手工实例化该类更方便
怎么实现?
利用已有的原型,快速生成和原型对象一样的实例
优点
- 性能提高
- 避免构造函数的约束
缺点
- 配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的简介对象,或者引用含有循环结构的时候
- 必须实现Cloneable接口
使用场景
- 资源优化场景
- 类初始化需要消化非常多的资源,包括数据、硬件资源等
- 性能和安全要求的场景
- 通过new产生一个对象非常需要繁琐的数据准备或访问权限
- 一个对象多个修改者的场景
- 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用
- 在实际项目中原型模式很少单独出现,一般和工厂模式一起出现,通过clone方法创建一个对象,然后又工厂提供给调用者
Considerations
与通过一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现Cloneable,重写,深拷贝是通过实现Serializable读取二进制流
代码
创建Shape抽象类,并实现Cloneable接口重写clone方法,使得每一个继承Shape类的类都可以使用clone方法
Shape.java
public abstract class Shape implements Cloneable { private String id; protected String type; abstract void draw(); public String getType() { return type; } public String getId() { return id; } public void setId(String id) { this.id = id; } @Override public Object clone() { Object clone = null; try { clone = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return clone; } }创建继承Shape抽象类的类
Rectangle.java
public class Rectangle extends Shape { public Rectangle() { type = "Rectangle"; } @Override public void draw() { System.out.println("This is Rectangle::draw() method."); } }Circle.java
public class Circle extends Shape { public Circle() { type = "Circle"; } @Override public void draw() { System.out.println("This is Circle::draw() method."); } }Square.java
public class Square extends Shape { public Square() { type = "Square"; } @Override public void draw() { System.out.println("This is Square::draw() method."); } }
创建一个类,从数据库中查询出实体类,并把它们存入Hashtable中
ShapeCache.java
import java.util.Hashtable; public class ShapeCache { private static Hashtable<String, Shape> shapeMap = new Hashtable<>(); public static Shape getShape(String shapeId) { return (Shape) shapeMap.get(shapeId).clone(); } //对每种形状都运行数据库查询,并创建该形状 public static void loadCache() { Circle circle = new Circle(); circle.setId("1"); shapeMap.put(circle.getId(), circle); Square square = new Square(); square.setId("2"); shapeMap.put(square.getId(), square); Rectangle rectangle = new Rectangle(); rectangle.setId("3"); shapeMap.put(rectangle.getId(), rectangle); } }
测试代码
PrototypePatternDemo.java
public class PrototypePatternDemo { public static void main(String[] args) { //先加载,从数据库中查询出所有的形状 ShapeCache.loadCache(); //查出来的并不是直接获取形状的实体类,而是其克隆的类 Shape cloneShape = ShapeCache.getShape("1"); System.out.println("Shape: " + cloneShape.getType()); cloneShape.draw(); Shape cloneShape2 = ShapeCache.getShape("2"); System.out.println("Shape: " + cloneShape2.getType()); cloneShape2.draw(); Shape cloneShape3 = ShapeCache.getShape("3"); System.out.println("Shape: " + cloneShape3.getType()); cloneShape3.draw(); } }
运行结果
![]()
UML类图
![]()