原型模式
在说明本模式的用处之前,我们先来举两个例子:
假设有1只羊,我们想利用克隆技术,来获得10只一模一样的羊,假设使用代码实现,我们可以使用以下代码:
public class Demo1 { public static void main(String[] args) { Sheep s = new Sheep("Wills",23); Sheep s1 = new Sheep(s.getName(),s.getAge()); Sheep s2 = new Sheep(s.getName(),s.getAge()); Sheep s3 = new Sheep(s.getName(),s.getAge()); } }
public class Demo1 { public static void main(String[] args) { Sheep s = new Sheep("Wills",23); Sheep s1 = new Sheep(s.getName(),s.getAge()); Sheep s2 = new Sheep(s.getName(),s.getAge()); Sheep s3 = new Sheep(s.getName(),s.getAge()); } }+ 优点是比较好理解,简单易操作 + 在创建新的对象时,总是急需要重新获取原始对象的属性,如果创新的对象比较复杂时,效率比较低 + 总是需要重新初始化对象,而不是动态获得对象运行时的状态,不够灵活
+ 优点是比较好理解,简单易操作 + 在创建新的对象时,总是急需要重新获取原始对象的属性,如果创新的对象比较复杂时,效率比较低 + 总是需要重新初始化对象,而不是动态获得对象运行时的状态,不够灵活public class Sheep implements Cloneable { private String name; private Integer age; // getter setter constructor .... @Override protected Object clone() throws CloneNotSupportedException { Sheep s = null; try{ s = (Sheep) super.clone(); }catch (Exception e){ System.out.println("克隆失败!"); } return s; } } public class Demo1 { public static void main(String[] args) throws CloneNotSupportedException { Sheep s = new Sheep("Wills",23); Sheep s1 = (Sheep) s.clone(); Sheep s2 = (Sheep) s.clone(); Sheep s3 = (Sheep) s.clone(); Sheep s4 = (Sheep) s.clone(); } }
public class Sheep implements Cloneable { private String name; private Integer age; // getter setter constructor .... @Override protected Object clone() throws CloneNotSupportedException { Sheep s = null; try{ s = (Sheep) super.clone(); }catch (Exception e){ System.out.println("克隆失败!"); } return s; } } public class Demo1 { public static void main(String[] args) throws CloneNotSupportedException { Sheep s = new Sheep("Wills",23); Sheep s1 = (Sheep) s.clone(); Sheep s2 = (Sheep) s.clone(); Sheep s3 = (Sheep) s.clone(); Sheep s4 = (Sheep) s.clone(); } }package com.wills.designMode.prototype; import java.io.Serializable; public class DeepCloneableTarget implements Cloneable, Serializable { private static final long seriaVerisonId = 1L; private String name; private String cloneClass; public DeepCloneableTarget(String name, String cloneClass) { this.name = name; this.cloneClass = cloneClass; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
package com.wills.designMode.prototype; import java.io.Serializable; public class DeepCloneableTarget implements Cloneable, Serializable { private static final long seriaVerisonId = 1L; private String name; private String cloneClass; public DeepCloneableTarget(String name, String cloneClass) { this.name = name; this.cloneClass = cloneClass; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }package com.wills.designMode.prototype; import com.sun.xml.internal.messaging.saaj.util.ByteInputStream; import java.io.*; public class DeepPrototype implements Serializable,Cloneable { private String name; public DeepCloneableTarget deepCloneableTarget; public DeepPrototype() { super(); } /** * 深拷贝示例1: 重写clone方法 * @return * @throws CloneNotSupportedException */ @Override protected Object clone() throws CloneNotSupportedException { Object deep = null; deep = super.clone(); // 强制转换为我们想要的类 DeepPrototype deepPrototype = (DeepPrototype) deep; deepPrototype.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone(); return deepPrototype; } /** * 深拷贝示例2:使用对象的序列化进行实现深拷贝 * 推荐!! */ 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); DeepPrototype deepPrototype = (DeepPrototype) ois.readObject(); return deepPrototype; }catch (Exception e){ e.printStackTrace(); return null; } finally { // 关闭流 try{ bos.close(); oos.close(); bis.close(); ois.close(); }catch (Exception e){ e.printStackTrace(); } } } } // 后续深拷贝实现只需要调用相应的方法即可
package com.wills.designMode.prototype; import com.sun.xml.internal.messaging.saaj.util.ByteInputStream; import java.io.*; public class DeepPrototype implements Serializable,Cloneable { private String name; public DeepCloneableTarget deepCloneableTarget; public DeepPrototype() { super(); } /** * 深拷贝示例1: 重写clone方法 * @return * @throws CloneNotSupportedException */ @Override protected Object clone() throws CloneNotSupportedException { Object deep = null; deep = super.clone(); // 强制转换为我们想要的类 DeepPrototype deepPrototype = (DeepPrototype) deep; deepPrototype.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone(); return deepPrototype; } /** * 深拷贝示例2:使用对象的序列化进行实现深拷贝 * 推荐!! */ 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); DeepPrototype deepPrototype = (DeepPrototype) ois.readObject(); return deepPrototype; }catch (Exception e){ e.printStackTrace(); return null; } finally { // 关闭流 try{ bos.close(); oos.close(); bis.close(); ois.close(); }catch (Exception e){ e.printStackTrace(); } } } } // 后续深拷贝实现只需要调用相应的方法即可<bean id="sheep" class="com.java.springtest.prototype.Sheep" scope="prototype"/>
<bean id="sheep" class="com.java.springtest.prototype.Sheep" scope="prototype"/>public class PrototypeTest { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml"); Sheep sheep = (Sheep) applicationContext.getBean("sheep"); System.out.println(sheep); } }
public class PrototypeTest { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml"); Sheep sheep = (Sheep) applicationContext.getBean("sheep"); System.out.println(sheep); } }public Object getBean(String name) throws BeansException { this.assertBeanFactoryActive(); //我们先进入getBeanFactory()方法,看看得到的是哪个BeanFactory,再寻找它的getBean()方法 return this.getBeanFactory().getBean(name); } //追踪发现这是一个抽象方法,应该是由AbstractApplicationContext的子类实现 public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
public Object getBean(String name) throws BeansException { this.assertBeanFactoryActive(); //我们先进入getBeanFactory()方法,看看得到的是哪个BeanFactory,再寻找它的getBean()方法 return this.getBeanFactory().getBean(name); } //追踪发现这是一个抽象方法,应该是由AbstractApplicationContext的子类实现 public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
同时可以发现AbstractBeanFactory也是BeanFactory的实现类
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { String beanName = this.transformedBeanName(name); Object sharedInstance = this.getSingleton(beanName); ................. if (mbd.isSingleton()) { sharedInstance = this.getSingleton(beanName, () -> { try { return this.createBean(beanName, mbd, args); } catch (BeansException var5) { this.destroySingleton(beanName); throw var5; } }); bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd); //判断了是否设置了原型模式 } else if (mbd.isPrototype()) { var11 = null; Object prototypeInstance; try { this.beforePrototypeCreation(beanName); //进入了原型模式的对象创建 prototypeInstance = this.createBean(beanName, mbd, args); } finally { this.afterPrototypeCreation(beanName); } bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { // ....... }
进入到doGetBean()方法可以发现,spring对参数进行了判断,对应创建了原型模式的对象
public Object getBean(String name) throws BeansException { return this.doGetBean(name, (Class)null, (Object[])null, false); }
从这个bean的父类的父类AbstractBeanFactory可以看到这个getBean(),同时调用了核心方法doGetBean();
去到DefaultListableBeanFactory中没有找到getBean()方法,于是往他的父类去找
private DefaultListableBeanFactory beanFactory; //实现了getBeanFactory方法,确保了线程安全的前提下返回了一个DefaultListableBeanFactory public final ConfigurableListableBeanFactory getBeanFactory() { synchronized(this.beanFactoryMonitor) { if (this.beanFactory == null) { throw new IllegalStateException("BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext"); } else { return this.beanFactory; } } }
发现在AbstractRefreshableApplicationContext中实现了这个方法,返回的是一个DefaultListableBeanFactory,也就是调用了DefaultListableBeanFactory的getBean()方法
往下找getBeanFactory()方法的实现
在创建ioc容器后,通过getBean()获取bean对象时,往里追可以发现在核心方法处spring对bean的scope属性进行了判断,配置了prototype时,进入了原型模式的使用
Spring中配置bean的时候,scope属性可以配置一个prototype值,该值指定该bean的创建是使用原型模式
在近期阅读Spring源码时,我看到在 Spring 中原型 bean 的创建,就是使用得原型设计模式
扩展:Spring中使用到的原型设计模式
创建新的对象比较复杂的时候,可以利用原型模式简化对象的创建过程,同时也能够提高效率
不用重新促使华对象,而是动态的获得对象运行时的状态
如果原始对象发生变化,其他克隆的对象也会发生相应的变化(因为默认是浅拷贝),无需修改代码
实现深克隆的时候可能需要比较复杂的代码
缺点: 需要为一个 类配备一个克隆的方法,这对全新的类来说不是很难,但是对已有的类进行改造的时候,需要修改其源代码,违背了OCP原则,这一点必须要注意!
原型模式的注意事项和细节
深拷贝应用实例
复制对象的所有基本数据类型的成员变量值
为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象,也就是说,对象进行深拷贝要对整个对象进行拷贝
深拷贝实现方式:
重写clone方法来实现深拷贝
通过对象序列化进行深拷贝(推荐)
深拷贝借本介绍
对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性复制一份给新的对象
对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组某个类的对象等,那么浅拷贝会进行引用传递,也就是将该成员变量的内存地址复制一份给新的对象(我们学C语言的就会有一个深刻的感受,尤其是指针那边)。因为实际上两个对象的该成员变量都指向同一个实例,在这种情况下,在一个对象中修改该成员变量会影响到另外一个对象的该成员变量值
克隆羊的例子就是一个浅拷贝
浅拷贝默认使用clone方法来实现
浅拷贝介绍
深拷贝与浅拷贝基本介绍
通过上述案例我们可以了解到简单的原型设计模式的使用了,但是这里就涉及到了深拷贝与浅拷贝
下面开始解决上面的克隆羊的问题:
Prototype:原型类,声明一个克隆自己的接口
ConcretePrototype 具体的原型类,实现一个克隆自己的操作
Clinet 让一个圆形对象克隆自己,从而创建一个新的对象
说明:
原型模式(prototype)是指:用原型实例指定创建帝乡的种类,并且通过拷贝这些原型,创建新的对象
原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节
工作原理是:通过一个圆形对象传给那个要发动创建的对象,这个要发动创建的对象通过请求圆形对象拷贝他们自己来实施创建,即对象.clone()
基本介绍
思路:Java中Object类是所有类的根类,Object提供了一个clone方法,该方法可以将一个Java对象复制一份,但是需要实现clone的Java对象必须时间Cloneable接口,该接口表示该类能够复制并且具有复制能力,这就是原型模式
上面的优缺点已经指出来了,那么我们开始说说如何改进吧:
但是这种是有优缺点的: