一)故事
个性化电子账单
二)定义
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
三)代码例子
共计一个类:1)原型类;
1)原型类
一个类
四)优点
1)性能优良
原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。
2)逃避构造函数的约束
这即是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的。优点就是减少了约束,缺点也是减少了约束,需要大家在实际应用时考虑。
五)缺点
六)使用场景
1)资源优化场景
类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
2)性能和安全要求的场景
通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
3)一个对象多个修改者的场景
一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
原型模式已经与Java融为一体了,随时拿来用,java.lang.Cloneable
七)注意事项
1)构造函数不会被执行
2)浅拷贝和深拷贝
浅拷贝,即拷贝引用,指向原生对象的内部元素地址,共享一个私有变量。
深拷贝,即完全拷贝,两个对象这间没有任何的瓜葛,你修改你的,我修改我的,不相互影响。
注:深拷贝和浅拷贝建议不要混合使用,特别是在涉及类的继承时,父类有多个引用的情况就非常复杂,建议的方案是深拷贝和浅拷贝分开实现。
3)clone与final两个冤家
对象clone与对象内的final关键字是有冲突的,想要实现拷贝,则删除掉final关键字,这是最便捷、安全、快捷的方式。你要使用clone方法,在类的成员变量上就不要增加final关键字。
注:要使用clone方法,类的成员变量上就不要增加final关键字。
八)扩展
九)总结
理解浅拷贝和深拷贝,浅拷贝是引用,浅拷贝是完全拷贝。基本类型,如:int,long,double和String对象(String对象看作是基本类型)都是深拷贝,而数组(如:Integer[]、Double[])和对象(如:ArrayList<String>、Version())都是浅拷贝。想要实现数组和对象的深拷贝,则在clone()方法里加入深拷贝代码,如下:
// 实现java.lang.Cloneable接口中的方法clone()
public class PrototypeClass implements java.lang.Cloneable {
// 数组与对象
private ArrayList<String> list = new ArrayList(); // 引用拷贝(浅拷贝)
private Version version = new Version();// 引用拷贝(浅拷贝)
private Integer[] integerArray = new Integer[6];// 引用拷贝(浅拷贝)
private int arrayIndex = 0;
// 覆盖父类Object方法
@Override
protected PrototypeClass clone() {
PrototypeClass prototype = null;
try {
// 浅拷贝
prototype = (PrototypeClass)super.clone();
// 对象深拷贝
prototype.list = (ArrayList<String>)this.list.clone();
// 对象深拷贝
prototype.version = (Version)this.version.clone();
// 数组深拷贝
prototype.integerArray = (Integer[])this.integerArray.clone();
} catch (CloneNotSupportedException ex) {
}
return prototype;
}
}
个性化电子账单
二)定义
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
三)代码例子
共计一个类:1)原型类;
1)原型类
/**
* 原型类
*
* @author levovo
*/
public class PrototypeClass implements java.lang.Cloneable {
private String title = null;// 完全拷贝(深拷贝)
private String name = null;// 完全拷贝(深拷贝)
private int number = 0; // 完全拷贝(深拷贝)
// 数组与对象
private ArrayList<String> list = new ArrayList(); // 引用拷贝(浅拷贝)
private Version version = new Version();// 引用拷贝(浅拷贝)
private Integer[] integerArray = new Integer[6];// 引用拷贝(浅拷贝)
private int arrayIndex = 0;
// static
private static Version versionStatic = new Version(); // 引用拷贝(浅拷贝)(仅有一个实例)
private static int numberStatic = 0;// 引用拷贝(浅拷贝)(仅有一个实例)
// final
private final Version versionFinal = new Version();
private final int numberFinal = 999;
// 覆盖父类Object方法
@Override
protected PrototypeClass clone() {
PrototypeClass prototype = null;
try {
// 浅拷贝
prototype = (PrototypeClass)super.clone();
// 对象深拷贝
prototype.list = (ArrayList<String>)this.list.clone();
// 对象深拷贝
prototype.version = (Version)this.version.clone();
// 数组深拷贝
prototype.integerArray = (Integer[])this.integerArray.clone();
} catch (CloneNotSupportedException ex) {
}
return prototype;
}
public void setTitle(String _title) {
this.title = _title;
// System.out.println("PrototypeClass()->setTitle():"+this.title);
}
public String getTitle() {
return this.title;
}
/**
* @return the number
*/
public int getNumber() {
return number;
}
/**
* @param number the number to set
*/
public void setNumber(int number) {
this.number = number;
}
public void setList(String value) {
this.getList().add(value);
}
public ArrayList<String> getList() {
return this.list;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @param list the list to set
*/
public void setList(ArrayList<String> list) {
this.list = list;
}
/**
* @return the version
*/
public Version getVersion() {
return version;
}
/**
* @param version the version to set
*/
public void setVersion(Version version) {
this.version = version;
}
/**
* @return the integerArray
*/
public Integer[] getIntegerArray() {
return integerArray;
}
/**
* @param integerArray the integerArray to set
*/
public void setIntegerArray(int integerArray) {
this.integerArray[arrayIndex] = integerArray;
}
/**
* @return the versionFinal
*/
public Version getVersionFinal() {
return versionFinal;
}
/**
* @return the numberFinal
*/
public int getNumberFinal() {
return numberFinal;
}
/**
* @return the versionStatic
*/
public static Version getVersionStatic() {
return versionStatic;
}
/**
* @param aVersionStatic the versionStatic to set
*/
public static void setVersionStatic(Version aVersionStatic) {
versionStatic = aVersionStatic;
}
/**
* @return the numberStatic
*/
public static int getNumberStatic() {
return numberStatic;
}
/**
* @param aNumberStatic the numberStatic to set
*/
public static void setNumberStatic(int aNumberStatic) {
numberStatic = aNumberStatic;
}
}
一个类
/**
* 一个类
*
* @author levovo
*/
public class Version implements java.lang.Cloneable {
private String name = null;
private int code = 0;
// 覆盖父类Object方法
@Override
protected Version clone() {
Version version = null;
try {
version = (Version)super.clone();
} catch (CloneNotSupportedException ex) {
}
return version;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the code
*/
public int getCode() {
return code;
}
/**
* @param code the code to set
*/
public void setCode(int code) {
this.code = code;
}
}
场景使用例子
/**
* 场景使用例子
*
* @author levovo
*/
public class Client {
public static void main(String[] args) {
// 旧的
PrototypeClass prototypeOld = new PrototypeClass();
prototypeOld.setTitle("titleOld");
String name = new String("nameOld");
prototypeOld.setName(name);
prototypeOld.setNumber(10001);
prototypeOld.setList("listOld");
prototypeOld.getVersion().setName("version name....Old");
prototypeOld.getVersion().setCode(20001);
prototypeOld.setIntegerArray(100);
prototypeOld.setNumberStatic(100);
prototypeOld.getVersionStatic().setName("version name...static...Old");
prototypeOld.getVersionStatic().setCode(30001);
// prototypeOld.set
// clone的
PrototypeClass prototypeClone = prototypeOld.clone();
// 修改
System.out.println("--- modify ---");
prototypeOld.setTitle("titleChange");
String name1 = new String("nameChange");
prototypeOld.setName(name1);
prototypeOld.setNumber(10002);
prototypeOld.setList("listChange");
prototypeOld.getVersion().setName("version name....Change");
prototypeOld.getVersion().setCode(20002);
prototypeOld.setIntegerArray(200);
prototypeOld.setNumberStatic(200);
prototypeOld.getVersionStatic().setName("version name...static...Change");
prototypeOld.getVersionStatic().setCode(30002);
System.out.println("--- 比较 ---");
// prototypeOld.getTitle().contains(name);
if (prototypeOld.getTitle().equals(prototypeClone.getTitle())) {
System.out.println("String title -> 属于引用拷贝(浅拷贝)");
}else{
System.out.println("String title -> 属于完全拷贝(深拷贝)");
}
if (prototypeOld.getName().equals(prototypeClone.getName())) {
System.out.println("String name -> 属于引用拷贝(浅拷贝)");
}else{
System.out.println("String name -> 属于完全拷贝(深拷贝)");
}
if (prototypeOld.getNumber() == prototypeClone.getNumber()) {
System.out.println("int number -> 属于引用拷贝(浅拷贝)");
}else{
System.out.println("int number -> 属于完全拷贝(深拷贝)");
}
if (prototypeOld.getList().equals(prototypeClone.getList())) {
System.out.println("ArrayList<String> list -> 属于引用拷贝(浅拷贝)");
}else{
System.out.println("ArrayList<String> list -> 属于完全拷贝(深拷贝)");
}
if (prototypeOld.getVersion().equals(prototypeClone.getVersion())) {
System.out.println("Version version -> 属于引用拷贝(浅拷贝)");
}else{
System.out.println("Version version -> 属于完全拷贝(深拷贝)");
}
if (prototypeOld.getVersion().getName().equals(prototypeClone.getVersion().getName())) {
System.out.println("Version version.getName() -> 属于引用拷贝(浅拷贝)");
}else{
System.out.println("Version version.getName() -> 属于完全拷贝(深拷贝)");
}
if (prototypeOld.getVersion().getCode() == prototypeClone.getVersion().getCode()) {
System.out.println("Version version.getCode() -> 属于引用拷贝(浅拷贝)");
}else{
System.out.println("Version version.getCode() -> 属于完全拷贝(深拷贝)");
}
System.out.println("prototypeOld.getIntegerArray()[0]:"+prototypeOld.getIntegerArray()[0]);
System.out.println("prototypeClone.getIntegerArray()[0]:"+prototypeClone.getIntegerArray()[0]);
if (prototypeOld.getIntegerArray()[0] == prototypeClone.getIntegerArray()[0]) {
System.out.println("Integer[] integerArray -> 属于引用拷贝(浅拷贝)");
}else{
System.out.println("Integer[] integerArray -> 属于完全拷贝(深拷贝)");
}
if (prototypeOld.getNumberStatic() == prototypeClone.getNumberStatic()) {
System.out.println("static int numberStatic -> 属于引用拷贝(浅拷贝)(仅一个实例)");
}else{
System.out.println("static int numberStatic -> 属于完全拷贝(深拷贝)");
}
if (prototypeOld.getVersionStatic().equals(prototypeClone.getVersionStatic())) {
System.out.println("static Version versionStatic -> 属于引用拷贝(浅拷贝)(仅一个实例)");
}else{
System.out.println("static Version versionStatic -> 属于完全拷贝(深拷贝)");
}
if (prototypeOld.getVersionStatic().getName().equals(prototypeClone.getVersionStatic().getName())) {
System.out.println("static Version versionStatic.getName() -> 属于引用拷贝(浅拷贝)(仅一个实例)");
}else{
System.out.println("static Version versionStatic.getName() -> 属于完全拷贝(深拷贝)");
}
if (prototypeOld.getVersionStatic().getCode() == prototypeClone.getVersionStatic().getCode()) {
System.out.println("static Version versionStatic.getCode() -> 属于引用拷贝(浅拷贝)(仅一个实例)");
}else{
System.out.println("static Version versionStatic.getCode() -> 属于完全拷贝(深拷贝)");
}
System.out.println("prototypeOld.getNumberFinal():"+prototypeOld.getNumberFinal());
System.out.println("prototypeClone.getNumberFinal():"+prototypeClone.getNumberFinal());
// 总论:
// 1)内部的数组(如Object[]和ArrayList<String>)和对象是拷贝引用,不是拷贝对象
// 2)基本类型是属于完全拷贝(深拷贝),String也算是基本类型
}
}
打印结果:
--- modify ---
--- 比较 ---
String title -> 属于完全拷贝(深拷贝)
String name -> 属于完全拷贝(深拷贝)
int number -> 属于完全拷贝(深拷贝)
ArrayList<String> list -> 属于完全拷贝(深拷贝)
Version version -> 属于完全拷贝(深拷贝)
Version version.getName() -> 属于完全拷贝(深拷贝)
Version version.getCode() -> 属于完全拷贝(深拷贝)
prototypeOld.getIntegerArray()[0]:200
prototypeClone.getIntegerArray()[0]:100
Integer[] integerArray -> 属于完全拷贝(深拷贝)
static int numberStatic -> 属于引用拷贝(浅拷贝)(仅一个实例)
static Version versionStatic -> 属于引用拷贝(浅拷贝)(仅一个实例)
static Version versionStatic.getName() -> 属于引用拷贝(浅拷贝)(仅一个实例)
static Version versionStatic.getCode() -> 属于引用拷贝(浅拷贝)(仅一个实例)
prototypeOld.getNumberFinal():999
prototypeClone.getNumberFinal():999
四)优点
1)性能优良
原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。
2)逃避构造函数的约束
这即是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的。优点就是减少了约束,缺点也是减少了约束,需要大家在实际应用时考虑。
五)缺点
六)使用场景
1)资源优化场景
类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
2)性能和安全要求的场景
通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
3)一个对象多个修改者的场景
一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
原型模式已经与Java融为一体了,随时拿来用,java.lang.Cloneable
七)注意事项
1)构造函数不会被执行
2)浅拷贝和深拷贝
浅拷贝,即拷贝引用,指向原生对象的内部元素地址,共享一个私有变量。
深拷贝,即完全拷贝,两个对象这间没有任何的瓜葛,你修改你的,我修改我的,不相互影响。
注:深拷贝和浅拷贝建议不要混合使用,特别是在涉及类的继承时,父类有多个引用的情况就非常复杂,建议的方案是深拷贝和浅拷贝分开实现。
3)clone与final两个冤家
对象clone与对象内的final关键字是有冲突的,想要实现拷贝,则删除掉final关键字,这是最便捷、安全、快捷的方式。你要使用clone方法,在类的成员变量上就不要增加final关键字。
注:要使用clone方法,类的成员变量上就不要增加final关键字。
八)扩展
九)总结
理解浅拷贝和深拷贝,浅拷贝是引用,浅拷贝是完全拷贝。基本类型,如:int,long,double和String对象(String对象看作是基本类型)都是深拷贝,而数组(如:Integer[]、Double[])和对象(如:ArrayList<String>、Version())都是浅拷贝。想要实现数组和对象的深拷贝,则在clone()方法里加入深拷贝代码,如下:
// 实现java.lang.Cloneable接口中的方法clone()
public class PrototypeClass implements java.lang.Cloneable {
// 数组与对象
private ArrayList<String> list = new ArrayList(); // 引用拷贝(浅拷贝)
private Version version = new Version();// 引用拷贝(浅拷贝)
private Integer[] integerArray = new Integer[6];// 引用拷贝(浅拷贝)
private int arrayIndex = 0;
// 覆盖父类Object方法
@Override
protected PrototypeClass clone() {
PrototypeClass prototype = null;
try {
// 浅拷贝
prototype = (PrototypeClass)super.clone();
// 对象深拷贝
prototype.list = (ArrayList<String>)this.list.clone();
// 对象深拷贝
prototype.version = (Version)this.version.clone();
// 数组深拷贝
prototype.integerArray = (Integer[])this.integerArray.clone();
} catch (CloneNotSupportedException ex) {
}
return prototype;
}
}