原型模式(Prototype Pattern) – 设计模式之创建型模式:
目录
原型模式(Prototype Pattern)
定义:Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
用原型实例制定创建对象的种类,并且通过拷贝这些原型创建新的对象。
从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。
一般在初始化的信息不发生变化的情况下,克隆是最好的办法,可以动态得获得对象运行时的状态。这既隐藏了对象创建的细节,又对性能是大大的提高。
知识点:
java 浅复制和深复制的进一步学习
C1: 浅复制
被复制的对象的所有变量都含有与原来的对象相同的值,而所有的其它对象的引用都仍然指向原来的对象。
C2:深复制
把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
C3:注意
使用原型模式时,引用的成员变量必须满足两个条件才不会被拷贝:一是类的成员变量,而不是方法内变量;二是必须是一个可变的引用对象,而不是一个原始类型或不可变对象。
内部的数组和引用对象才不拷贝,其他的原始类型比如int、long、char等都会被拷贝
原型模式主要是重写clone() 的方法
类图
原型模式通用类图:
例子-形状:
过程:
在学画画的时候,会话很多基础的图形,比如三角形,圆形和矩形等。
这个例子比较简单,主要是对象实现Cloneable接口,重新clone()方法
代码:
形状 Shape 实现 Cloneable
public class Shape implements Cloneable {
private String color;
private String type;
public Shape(String color, String type) {
this.color = color;
this.type = type;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
@Override
public String toString() {
return "Shape{" +
"color='" + color + '\'' +
", type='" + type + '\'' +
'}';
}
}
测试:
public class ShapeTest {
private static final String COLORS[] =
{ "红色", "粉红色", "绿色", "蓝色", "棕色", "橘色" };
private static final String SHAPES[] =
{ "圆形", "三角形", "长方形", "平行四边形", "扇形", "梯形" };
public static void main(String[] args) {
// 先造一个原型
Shape prototypeShape = new Shape(getRandomColor(), getRandomShape());
for(int i=0; i < 10; ++i) {
Shape clone = (Shape) prototypeShape.clone();//复制原型
clone.setColor(getRandomColor());
clone.setType(getRandomShape());
System.out.println(clone.toString());
}
}
private static String getRandomColor() {
return COLORS[(int)(Math.random()*COLORS.length)];
}
private static String getRandomShape() {
return SHAPES[(int)(Math.random()*COLORS.length)];
}
}
结果:
Shape{color='绿色', type='扇形'}
Shape{color='绿色', type='梯形'}
Shape{color='橘色', type='三角形'}
Shape{color='红色', type='扇形'}
Shape{color='红色', type='长方形'}
Shape{color='绿色', type='圆形'}
Shape{color='棕色', type='圆形'}
Shape{color='蓝色', type='三角形'}
Shape{color='棕色', type='扇形'}
Shape{color='绿色', type='扇形'}
复制后,动态进行设置了其它的属性
总结:
优点:
1、性能提高。
2、逃避构造函数的约束。
缺点:
1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
2、必须实现 Cloneable 接口。
使用场景
1,资源优化场景 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
2,性能和安全要求的场景 通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
3, 一个对象多个修改者的场景 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与Java融为一体,可以随手拿来使用。