动机
现代的编程都是基于成本考虑的。当涉及到使用计算机资源时,“节约”便是一个大问题,因此程序员们都竭尽全力来寻找方式来提升程序的性能。当我们谈论对象创建时,我们可以找到一个更好的方式来产生一个对象:克隆。而有一个设计模式是与之相关的:它没有创建对象,而是克隆了一个对象。如果创建一个对象的成本是比较大的并且创建动作是资源密集型的,那么我们便“克隆”这个对象。
原型设计模式正是问题所在。其允许一个对象创建自定义的对象,而不需要了解它们的类以及任何创建它们的细节。说到这点,它听起来很像工厂方法模式,而它们的区别在于对于工厂来说,原型对象的调色板从不包含多个对象。
意图
- 使用原型实例来指定要创建的对象的种类
- 通过拷贝原型来创建新的对象
实现
原型模式使用了抽象类,如同我们会在下面看到的,以及仅仅三个类来使得其实现变得相当简单。
原型模式的参与类列举如下:
Client:通过请求原型克隆自己来创建一个新的对象
Prototype:声明一个克隆自己的接口
ConcreteProtoType:实现了克隆自己的操作
克隆过程开始于一个已初始化及实例化的类。Client请求一个那个类的新对象并且将请求送到原型类中。ConcretePrototype将通过Clone()方法进行克隆,从而创建一个其本身的新实例。
这是原型模式的示例代码:
public interface Prototype { public abstract Object clone ( ); } public class ConcretePrototype implements Prototype { public Object clone() { return super.clone(); } } public class Client { public static void main( String arg[] ) { ConcretePrototype obj1= new ConcretePrototype (); ConcretePrototype obj2 = (ConcretePrototype)obj1.clone(); } }
这个例子非常琐碎,但是当我们不知道我们在克隆什么的时候才是这个模式的真正用处所在。比如,如果我们需要将新创建的对象存储在哈希表里,我们可以这样使用它:
// Violation of Likov's Substitution Principle class Rectangle { protected int m_width; protected int m_height; public void setWidth(int width){ m_width = width; } public void setHeight(int height){ m_height = height; } public int getWidth(){ return m_width; } public int getHeight(){ return m_height; } public int getArea(){ return m_width * m_height; } } class Square extends Rectangle { public void setWidth(int width){ m_width = width; m_height = width; } public void setHeight(int height){ m_width = height; m_height = height; } } class LspTest { private static Rectangle getNewRectangle() { // it can be an object returned by some factory ... return new Square(); } public static void main (String args[]) { Rectangle r = LspTest.getNewRectangle(); r.setWidth(5); r.setHeight(10); // user knows that r it's a rectangle. // It assumes that he's able to set the width and height as for the base class System.out.println(r.getArea()); // now he's surprised to see that the area is 100 instead of 50. } }