1.原型模式是什么
1.百度百科
原型模式(Prototype Patten);用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
2.维基百科
The prototype pattern is a creational design pattern in software development. It is used when the type of objects to create is determined by a prototypical instance, which is cloned to produce new objects. This pattern is used to:
avoid subclasses of an object creator in the client application, like the factory method pattern does.
avoid the inherent cost of creating a new object in the standard way (e.g., using the 'new' keyword) when it is prohibitively expensive for a given application.
To implement the pattern, declare an abstract base class that specifies a pure virtual clone() method. Any class that needs a "polymorphic constructor" capability derives itself from the abstract base class, and implements the clone() operation.
The client, instead of writing code that invokes the "new" operator on a hard-coded class name, calls the clone() method on the prototype, calls a factory method with a parameter designating the particular concrete derived class desired, or invokes the clone() method through some mechanism provided by another design pattern.
The mitotic division of a cell — resulting in two identical cells — is an example of a prototype that plays an active role in copying itself and thus, demonstrates the Prototype pattern. When a cell splits, two cells of identical genotype result. In other words, the cell clones itself
3.lz理解
原型模式将的就是将一个对象克隆成另外一个对象。完全复制对象并不执行构造方法
4.核心角色
抽象原型(Prototype)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体原型类所需的接口。在java中,抽象原型角色通常实现了Cloneable接口。
具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口。
原型管理器(Prototype Manager)角色:创建具体原型类的对象,并记录每一个被创建的对象。
2.原型模式解决了什么问题
复杂对象创建速度慢 由于克隆是JVM直接复制对象所在内存块,所以速度非常快。
规避构造方法限制 由于是直接复制并不执行该对象中的构造方法。
3.原型模式用法
原型的克隆分为两种,一种为浅复制。即为只复制对象中的基本成员变量,引用成员变量只是复制引用。并不复制引用内容。
public class Prototype implements Cloneable {
private int x;
private int y;
public Prototype(int x, int y) {
super();
this.x = x;
this.y = y;
System.out.println("构造方法被执行了");
}
public void change(int x, int y) {
this.x = x;
this.y = y;
}
public Prototype clone() {
Object object = null;
try {
object = super.clone();
} catch (CloneNotSupportedException exception) {
throw new RuntimeException(exception);
}
return (Prototype) object;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public String toString() {
return "Prototype [x=" + x + ", y=" + y + "]";
}
public static void main(String[] args) {
Prototype p1 = new Prototype(10, 10);
Object p2 = p1.clone();
System.out.println(p1.equals(p2));
}
}
对该代码稍加改造就能看出是否为浅复制
public class Prototype implements Cloneable {
private int x;
private int y;
private Point point;
public Prototype(int x, int y) {
super();
this.x = x;
this.y = y;
point = new Point(x, y);
System.out.println("构造方法被执行了");
}
public void change(int x, int y) {
this.x = x;
this.y = y;
}
public Prototype clone() {
Object object = null;
try {
object = super.clone();
} catch (CloneNotSupportedException exception) {
throw new RuntimeException(exception);
}
return (Prototype) object;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public Point getPoint() {
return point;
}
public void setPoint(Point point) {
this.point = point;
}
@Override
public String toString() {
return "Prototype [x=" + x + ", y=" + y + ", point=" + point + "]";
}
public static void main(String[] args) {
Prototype p1 = new Prototype(10, 10);
Prototype p2 = p1.clone();
System.out.println(p1.equals(p2));
System.out.println(p1.getPoint());
System.out.println(p2.getPoint());
}
}
结果
构造方法被执行了
false
com.yanlong.prototypePatten.example.Point@33909752
com.yanlong.prototypePatten.example.Point@33909752
两个对象的引用地址完全一样
浅复制非常简单,那么如何实现深复制呢。
如下
public class Point implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1377063653952262822L;
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
private int x;
private int y;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
public class Client {
public static void main(String[] args) {
DeepPrototype deep1 = new DeepPrototype(10,10);
deep1.setPoint(new Point(2, 3));
//深拷贝
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(deep1);
byte[] bytes = bos.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
DeepPrototype deep2 = (DeepPrototype) ois.readObject();
System.out.println(deep1.equals(deep2));
System.out.println(deep1.getPoint());
System.out.println(deep2.getPoint());
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果
构造方法被执行了
false
com.yanlong.prototypePatten.example.Point@7d4991ad
com.yanlong.prototypePatten.example.Point@448139f0
应用地址也不一样
4.原型模式的问题
链表结构对象容易死循环 配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
JVM底层写好实现 必须实现 Cloneable 接口,灵活性较差想实现深复制必须重写方法。
构造方法无法限制对象 逃避构造函数的约束。
5.原型模式总结
应用场景:
1、对象的创建非常复杂,可以使用原型模式快捷的创建对象。
2、在运行过程中不知道对象的具体类型,可使用原型模式创建一个相同类型的对象,或者在运行过程中动态的获取到一个对象的状态。
碎碎念:
有的时候一个巨大的对象创建起来非常浪费时间。我们想最好是有一种很简单的解决办法能非常迅速的构建一个新的对象。原型模式就是来解决这个问题的。但是原型模式非常害怕循环调用。或者说是递归调用。所以在使用原型模式一定要从全局考虑是否适用。
引用
http://www.cnblogs.com/zuoxiaolong/p/pattern24.html
http://blog.csdn.net/li12412414/article/details/52195152