一、什么是原型模式
原型模式(Prototype),用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。UML结构图如下:
其中,Prototype为原型类,声明一个克隆自身的接口;ConcretePrototype为具体实现类,实现一个克隆自身的操作;而客户端Client只需让一个原型克隆自身,从而创建一个新的对象。
1. Prototype
public abstract class Prototype implements Cloneable { private String id; public Prototype(String id) { this.id = id; } public String getId() { return id; } @Override public Prototype clone() { Prototype prototype = null; try { prototype = (Prototype) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return prototype; } }
2. ConcretePrototype
创建当前对象的浅表副本。
public class ConcretePrototype extends Prototype { public ConcretePrototype(String id) { super(id); } }
3. Client
public class Client { public static void main(String[] args) { ConcretePrototype p1 = new ConcretePrototype("Hello"); ConcretePrototype c1 = (ConcretePrototype) p1.clone(); System.out.println(c1.getId()); } }
运行结果为“Hello”,此时ConcretePrototype的对象p1得到了新的实例c1。
二、原型模式的应用
1. 何时使用
- 当一个系统应该独立于它的产品创建、构成和表示时。
- 当要实例化的类是在运行时刻指定时(如动态装载)。
- 为了避免创建一个与产品类层次平行的工厂类层次时。
- 当一个类的实例只能有几种几个不同状态组合中的一种时。
2. 优点
- 性能优良。不用重新初始化对象,而是动态地获取对象运行时的状态。
- 逃避构造函数的约束。
3. 缺点
- 配置克隆方法需要对类的功能进行通盘考虑。
- 必须实现Cloneable接口。
4. 使用场景
- 资源优化场景。
- 性能和安全要求的场景。
- 一个对象多个修改者的场景。
- 一般与工厂方法模式一起出现,通过clone方法创建一个对象,然后由工厂方法提供给调用者。
5. 应用实例
- 细胞分裂
- Java中的Object.clone()方法
- 复印
三、原型模式的实现
下面我们创建一个抽象类和扩展了它的实体类,即图形类与圆形、矩形、三角形。之后再通过一个cache类将对象存储在一个Hashtable中,并在请求的时候返回它们的克隆。UML图如下:
1. Shape类
创建一个实现了Cloneable接口的抽象类。
public abstract class Shape implements Cloneable { private String id; protected String type; public abstract void draw(); public String getId() { return id; } public void setId(String id) { this.id = id; } public String getType() { return type; } @Override public Shape clone() { Shape prototype = null; try { prototype = (Shape) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return prototype; } }
2. 实现类
创建扩展了上面抽象类的实现类,这里以Circle为例。
public class Circle extends Shape { public Circle() { type = "圆形"; } @Override public void draw() { System.out.println("圆形类的draw方法"); } }
3. ShapeCache
获取实体类,并存于Hashtable中。
public class ShapeCache { private static Hashtable<String, Shape> shapeMap = new Hashtable<>(); public static Shape getShape(String shapeId) { Shape shape = shapeMap.get(shapeId); return shape.clone(); } //添加三种图形 public static void loadCache() { Circle circle = new Circle(); circle.setId("1"); shapeMap.put(circle.getId(), circle); Triangle triangle = new Triangle(); triangle.setId("2"); shapeMap.put(triangle.getId(), triangle); Rectangle rectangle = new Rectangle(); rectangle.setId("3"); shapeMap.put(rectangle.getId(), rectangle); } }
4. Client客户端
public class Client { public static void main(String[] args) { ShapeCache.loadCache(); Shape clonedShape = ShapeCache.getShape("1"); System.out.println("图形:" + clonedShape.getType()); Shape clonedShape2 = ShapeCache.getShape("2"); System.out.println("图形:" + clonedShape2.getType()); Shape clonedShape3 = ShapeCache.getShape("3"); System.out.println("图形:" + clonedShape3.getType()); } }
运行结果如下: