创建型——原型模式(Prototype)day05

    技术2024-10-31  22

    原型模式基本介绍

    原型模式Prototype也称为克隆模式原型模式(Prototype模式)是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即对象.clone()实现原型模式需要实现标记型接口Cloneable一般会重写clone()方法 如果只是重写clone()方法,而没实现接口,调用时会报异常一般用于一个对象的属性已经确定,需要产生很多相同对象的时候需要区分深克隆与浅克隆形象的理解:孙大圣拔出猴毛,变出其它孙大圣

    原型模式UML图

    ➢原理结构图说明

    Prototype: 原型类,声明一个克隆自己的接口ConcretePrototype: 具体的原型类,实现-一个克隆自己的操作Client: 让一个原型对象克隆自己,从而创建一一个新的对象(属性一样)

    浅克隆

    浅克隆,如果被克隆类有一个属性是其他的对象,那么它克隆出来的对象会互相干扰。

    package com.xhl.prototype; //浅克隆,如果克隆location就会相互影响 public class Text { public static void main(String[] args) throws CloneNotSupportedException { // TODO Auto-generated method stu Person p1 = new Person(); Person p2 = (Person)p1.clone(); System.out.println(p2.age+" "+p2.score); System.out.println(p2.loc); System.out.println(p1.loc==p2.loc); p1.loc.street="sh"; System.out.println(p2.loc); } } class Person implements Cloneable{ int age = 8; int score = 100; Location loc = new Location("bj",22); @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone(); } } class Location{ String street; int roomNo; @Override public String toString() { // TODO Auto-generated method stub return "Lacation["+ "street='"+street+ ",roomNo="+roomNo+ "]"; } public Location(String street, int roomNo) { super(); this.street = street; this.roomNo = roomNo; } }

    原因: 总结:

    对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。

    深克隆

    第一种方法

    package com.xhl.prototype; //深克隆 public class Text1 { public static void main(String[] args) throws CloneNotSupportedException { // TODO Auto-generated method stu Person1 p1 = new Person1(); Person1 p2 = (Person1)p1.clone(); System.out.println(p2.age+" "+p2.score); System.out.println(p2.loc); System.out.println(p1.loc==p2.loc); p1.loc.street="sh"; System.out.println(p2.loc); } } class Person1 implements Cloneable{ int age = 8; int score = 100; Location1 loc = new Location1("bj",22); @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub Person1 p = (Person1)super.clone(); p.loc = (Location1)loc.clone(); return p; } } class Location1 implements Cloneable{ String street; /* * String类型也是引用类型, * 但是不需要进行深克隆 * 因为String类型指向的是一个常量池 * 本身就是共用的 */ int roomNo; @Override public String toString() { // TODO Auto-generated method stub return "Lacation["+ "street='"+street+ ",roomNo="+roomNo+ "]"; } public Location1(String street, int roomNo) { super(); this.street = street; this.roomNo = roomNo; } @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone(); } }

    第二种方法

    package com.xhl.prototype; //深克隆 import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class Text1 { public static void main(String[] args) throws CloneNotSupportedException { // TODO Auto-generated method stu Person1 p1 = new Person1(); //Person1 p2 = (Person1)p1.clone(); Person1 p2 = (Person1) p1.deepClone(); System.out.println(p2.age+" "+p2.score); System.out.println(p2.loc); System.out.println(p1.loc==p2.loc); p1.loc.street="sh"; System.out.println(p2.loc); } } class Person1 implements Cloneable,Serializable{ int age = 8; int score = 100; Location1 loc = new Location1("bj",22); //方法一 @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub Person1 p = (Person1)super.clone(); p.loc = (Location1)loc.clone(); return p; } //方法二 通过对象序列化实现 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); Person1 p = (Person1)ois.readObject(); return p; } catch (Exception e) { // TODO: handle exception e.printStackTrace(); return null; }finally { try { bos.close(); oos.close(); bis.close(); ois.close(); } catch (Exception e2) { // TODO: handle exception System.out.println(e2.getMessage()); } } } } class Location1 implements Cloneable,Serializable{ String street; /* * String类型也是引用类型, * 但是不需要进行深克隆 * 因为String类型指向的是一个常量池 * 本身就是共用的 */ int roomNo; @Override public String toString() { // TODO Auto-generated method stub return "Lacation["+ "street='"+street+ ",roomNo="+roomNo+ "]"; } public Location1(String street, int roomNo) { super(); this.street = street; this.roomNo = roomNo; } @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone();

    总结:

    复制对象的所有基本数据类型的成员变量值为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象(包括对象的引用类型)进行拷贝

    原型模式注意事项和细节

    创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率不用重新初始化对象,而是动态地获得对象运行时的状态如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码在实现深克隆的时候可能需要比较复杂的代码缺点:需要为每一个类配备一个克隆方法, 这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了ocp(开闭) 原则。

    原型模式在Spring框架中源码分析

    Spring中原型bean的创建,就是原型模式的应用代码分析+Debug源码

    Processed: 0.009, SQL: 9