创建型设计模式之原型模式
原型模式:用原型实例指定创建对象的种类,并通过拷贝这些原型,创建新的对象。
拷贝分为浅拷贝和深拷贝
浅拷贝:
对于基本数据类型,直接进行值传递,即将该属性值复制一份给新的对象
对于引用数据类型,会进行引用传递,会该将成员变量的引用值(内存地址)复制一份给新的对象,实际上两个成员变量都指同一个实例,修改其中一个成员变量的值,会影响到另一个成员变量的值。
实现方式:继承Cloneable,使用默认的clone()实现。
深拷贝:
在浅拷贝的基础上,为引用类型变量申请存储空间,并复制每个引用类型成员变量所引用的对象,修改其中一个成员变量的值,不会影响另一个成员变量的值。
实现方式一:继承Cloneable,重写clone()方法实现
实现方式二:通过对象序列化实现深拷贝(推荐)
代码实现:
男孩有条狗,女孩有条狗
女孩浅拷贝
男孩深拷贝
狗实例
public class Dog implements Cloneable, Serializable { private int age; private String name; public Dog(int age, String name){ this.age=age; this.name=name; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Dog{" + "age=" + age + ", name='" + name + '\'' + '}'; } }
女孩有狗浅拷贝实现
/** * 浅复制的复制不彻底,忽略了引用数据类型 * 浅复制代码实现:通过实现Cloneable接口,并覆写其clone方法。 */ public class Girl implements Cloneable { private int age; private String name; private Dog dog; public Girl(int age, String name, Dog dog){ this.age=age; this.name=name; this.dog=dog; } @Override protected Object clone() throws CloneNotSupportedException { return (Girl)super.clone(); } @Override public String toString() { return "Girl{" + "age=" + age + ", name='" + name + '\'' + ", dog=" + dog + '}'; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Dog getDog() { return dog; } public void setDog(Dog dog) { this.dog = dog; } }
男孩深拷贝代码实现:
/** * 深复制 * 其中Disk属性是引用对象,要实现Disk对象的复制,需使用深复制 * 具体操作是引用对象需实现Cloneable接口并覆写clone(),然后在复杂对象中声明式将引用对象复制出来赋值给引用对象的属性。 */ public class Boy implements Cloneable, Serializable { private int age; private String name; private Dog dog; public Boy(int age, String name, Dog dog){ this.age=age; this.name=name; this.dog=dog; } /** * 重写clone实现深拷贝 * @return * @throws CloneNotSupportedException */ @Override protected Object clone() throws CloneNotSupportedException { Boy boy = (Boy) super.clone(); //深拷贝 boy.dog=(Dog)this.dog.clone(); return boy; } /** * 使用序列化方式深拷贝(推荐) * @return */ public Object deepClone(){ ByteArrayOutputStream bos=null; ObjectOutputStream oos=null; ByteArrayInputStream bis=null; ObjectInputStream ois=null; try{ //序列化 bos=new ByteArrayOutputStream(); oos=new ObjectOutputStream(bos); //当前这个对象以对象流的方式输出 oos.writeObject(this); //反序列化 bis = new ByteArrayInputStream(bos.toByteArray()); ois=new ObjectInputStream(bis); Boy boy =(Boy)ois.readObject(); return boy; } catch (Exception e){ e.printStackTrace(); return null; } } @Override public String toString() { return "Boy{" + "age=" + age + ", name='" + name + '\'' + ", dog=" + dog + '}'; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Dog getDog() { return dog; } public void setDog(Dog dog) { this.dog = dog; } }
使用原型模型
/** * 使用原型模型 */ public class Main { public static void main(String[] args) throws Exception{ Dog dog_girl = new Dog(1,"旺财"); Dog dog_boy = new Dog(2,"泰迪"); //浅复制 Girl girl = new Girl(18,"小红",dog_girl); Girl girlClone = (Girl) girl.clone(); System.out.println(girl.toString()); System.out.println(girlClone.toString()); //浅复制会将变量的引用值(内存地址)复制给一份给新的对象,实现上两个成员变量指向的是同一个实例,修改一个对象的值会影响另一个对象的值 System.out.println(girl.getDog().hashCode()+" "+girlClone.getDog().hashCode()); girl.getDog().setName("旺财啊");//引用类型,同时会改变克隆girlClone的值 girl.setAge(20); girl.setName("小红红"); System.out.println(girl.toString()); System.out.println(girlClone.toString()); System.out.println("------深拷贝----------------"); //深复制 Boy boy = new Boy(32,"小明",dog_boy); //深拷贝实现方式一:重写clone //Boy boyClone = (Boy) boy.clone(); //深拷贝实现方式二:序列化(推荐) Boy boyClone = (Boy) boy.deepClone(); System.out.println(boy.toString()); System.out.println(boyClone.toString()); //深复制为引用类型变量申请存储空间,并复制每个引用类型成员变量所引用的对象 System.out.println(boy.getDog().hashCode()+" "+boyClone.getDog().hashCode()); boy.getDog().setName("泰迪啊");//深复制,不会改变克隆boyClone的值 boy.setAge(20); boy.setName("明明"); System.out.println(boy.toString()); System.out.println(boyClone.toString()); } }
运行结果:
Girl{age=18, name='小红', dog=Dog{age=1, name='旺财'}} Girl{age=18, name='小红', dog=Dog{age=1, name='旺财'}} 685325104 685325104 Girl{age=20, name='小红红', dog=Dog{age=1, name='旺财啊'}} Girl{age=18, name='小红', dog=Dog{age=1, name='旺财啊'}} ------深拷贝---------------- Boy{age=32, name='小明', dog=Dog{age=2, name='泰迪'}} Boy{age=32, name='小明', dog=Dog{age=2, name='泰迪'}} 1173230247 1639705018 Boy{age=20, name='明明', dog=Dog{age=2, name='泰迪啊'}} Boy{age=32, name='小明', dog=Dog{age=2, name='泰迪'}}
Spring框架中bean多例的创建,就是原型模型的应用。默认实现浅拷贝,对处理结果做了缓存来提升性能。