聊城找个人做网站,广西城乡和建设厅网站首页,有哪些网站可以做任务返现,中陕核建设集团网站文章目录 1 基本介绍2 实现方式深浅拷贝目标2.1 使用 Object 的 clone() 方法2.1.1 代码2.1.2 特性2.1.3 实现深拷贝 2.2 在 clone() 方法中使用序列化2.2.1 代码 2.2.2 特性 3 实现的要点4 Spring 中的原型模式5 原型模式的类图及角色5.1 类图5.1.1 不限制语言5.1.2 在 Java 中… 文章目录 1 基本介绍2 实现方式深浅拷贝目标2.1 使用 Object 的 clone() 方法2.1.1 代码2.1.2 特性2.1.3 实现深拷贝 2.2 在 clone() 方法中使用序列化2.2.1 代码 2.2.2 特性 3 实现的要点4 Spring 中的原型模式5 原型模式的类图及角色5.1 类图5.1.1 不限制语言5.1.2 在 Java 中的类图 5.2 角色5.2.1 Prototype ( 原型 )5.2.2 ConcretePrototype ( 具体的原型 )5.2.3 Client ( 使用者 ) 6 原型模式的优缺点7 原型模式的使用场景8 总结 1 基本介绍
原型模式Prototype Pattern是一种创建型设计模式它允许 通过复制已有的对象来创建新的对象而无需知道对象创建的细节。
2 实现方式
深浅拷贝
原型模式的实现围绕着 深浅拷贝 的特性展开其定义如下
浅拷贝Shallow Copy只复制对象的 第一层 属性即 八大基本数据类型 String 这个引用数据类型对于引用类型的属性除了字符串 String 类型外复制的是内存地址引用而非对象本身。它存在这种危险如果原对象的引用类型属性被修改浅拷贝得到的对象的对应属性也会受到影响。深拷贝Deep Copy递归地 复制对象及其所有子对象创建一个全新的对象与原对象没有任何关联。
目标
实现一个 Sheep 类字段为 String name 和 int age它能通过 clone() 方法克隆出一模一样的对象。
共有以下 2 种实现
2.1 使用 Object 的 clone() 方法
2.1.1 代码
public class Sheep implements Cloneable { // 实现了 Cloneable 接口private String name;private int age;private String friend;public Sheep(String name, int age, String friend) {this.name name;this.age age;this.friend friend;}public String getName() {return name;}public int getAge() {return age;}public String getFriend() {return friend;}Overridepublic Sheep clone() {try {return (Sheep) super.clone(); // 使用 Object 的 clone()} catch (Exception e) { // 如果有异常e.printStackTrace(); // 打印异常return null; // 并返回 null}}public static void main(String[] args) { // 测试程序Sheep sheep new Sheep(silvery, 6, new Sheep(gold, 13, null));Sheep clone sheep.clone();System.out.println(sheep clone);System.out.println([sheep]: name sheep.getName() , age sheep.getAge() , friend sheep.getFriend() , friend.name sheep.getFriend().getName());System.out.println([clone]: name clone.getName() , age clone.getAge() , friend clone.getFriend() , friend.name clone.getFriend().getName());/* 测试结果如下false[sheep]: name silvery, age 6, friend cn.me.Sheepf6f4d33, friend.name gold[clone]: name silvery, age 6, friend cn.me.Sheepf6f4d33, friend.name gold总结sheep 和 name 不是同一个对象但属性一样它们的 friend 是同一个 friend这就是 浅拷贝*/}
}2.1.2 特性
浅拷贝Object 自带的 clone() 方法是浅拷贝对于非 String 类型的引用类型它只能拷贝其内存地址。实现简单虽然这种方式是浅拷贝但实现起来很简单如果能确定不使用除 String 类型之外的引用类型这种方式很方便。
2.1.3 实现深拷贝
如果一个类中除 String 类型之外的引用类型 很少那么可以像以下这样 单独 对这些引用类型进行 克隆从而实现深拷贝
Override
public Sheep clone() {try {Sheep clone (Sheep) super.clone();// 对 除 String 之外的引用类型 单独克隆// 如果没有判断空值则可能会抛出空指针异常 NullPointerExceptionif (clone.friend ! null) {clone.friend this.friend.clone();}return clone;} catch (Exception e) { // 如果有异常e.printStackTrace(); // 打印异常return null; // 并返回 null}
}2.2 在 clone() 方法中使用序列化
2.2.1 代码
注意如果要使用序列化则要实现 Serializable 接口。
public class Sheep implements Cloneable, Serializable { // 实现了 Cloneable 和 Serializable 接口private String name;private int age;private String friend;public Sheep(String name, int age, String friend) {this.name name;this.age age;this.friend friend;}public String getName() {return name;}public int getAge() {return age;}public String getFriend() {return friend;}Overridepublic Sheep clone() {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);Object clone ois.readObject();return (Sheep) clone;} catch (Exception e) { // 如果有异常e.printStackTrace(); // 打印异常return null; // 并返回 null} finally {try { // 用完流之后记得关闭if (bos ! null) {bos.close();}if (oos ! null) {oos.close();}if (bis ! null) {bis.close();}if (ois ! null) {ois.close();}} catch (Exception e) { // 如果关闭流出现异常e.printStackTrace(); // 则打印异常}}}public static void main(String[] args) { // 测试程序Sheep sheep new Sheep(silvery, 6, new Sheep(gold, 13, null));Sheep clone sheep.clone();System.out.println(sheep clone);System.out.println([sheep]: name sheep.getName() , age sheep.getAge() , friend sheep.getFriend() , friend.name sheep.getFriend().getName());System.out.println([clone]: name clone.getName() , age clone.getAge() , friend clone.getFriend() , friend.name clone.getFriend().getName());/* 测试结果如下false[sheep]: name silvery, age 6, friend cn.me.Sheep421faab1, friend.name gold[clone]: name silvery, age 6, friend cn.me.Sheep504bae78, friend.name gold总结sheep 和 name 不是同一个对象但属性一样它们的 friend 不是同一个 friend但属性一样这是 深拷贝*/}
}2.2.2 特性
深拷贝这种方式是深拷贝它会递归地构建所有对象从而创建一个与原对象无任何关联的新对象只是属性相同罢了。实现复杂这种方式的实现很复杂涉及到四个流的创建、使用和关闭要处理的异常也很多。性能开销这种方式由于需要创建、使用和关闭流所以可能会消耗一部分性能。
3 实现的要点
实现 Cloneable 接口。重写 Object 类的 clone() 方法。考虑深浅拷贝的问题。
4 Spring 中的原型模式
对于 ClassPathXmlApplicationContext 类的对象它的 getBean() 方法继承自 AbstractBeanFactory 抽象类的 getBean() 方法其内部调用了 doGetBean() 方法在 doGetBean() 方法中使用了原型模式这里面具体的逻辑就很复杂了如下所示
protected T T doGetBean(String name, Nullable ClassT requiredType, Nullable Object[] args,boolean typeCheckOnly) throws BeansException {// ...else if (mbd.isPrototype()) {prototypeInstance null;Object prototypeInstance;try {this.beforePrototypeCreation(beanName);prototypeInstance this.createBean(beanName, mbd, args); // 在这里使用了原型模式} finally {this.afterPrototypeCreation(beanName);}beanInstance this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}// ...
}5 原型模式的类图及角色
5.1 类图
5.1.1 不限制语言 5.1.2 在 Java 中的类图 5.2 角色
5.2.1 Prototype ( 原型 )
该角色负责 定义 用于复制现有实例来生成新实例的 方法在 Java 中一般指的是 Object 类它定义了 native 的 clone() 方法。
5.2.2 ConcretePrototype ( 具体的原型 )
该角色负责 实现 用于复制现有实例来生成新实例的 方法在 Java 中不仅要继承 Object 类(如果一个类不指定继承的类则它默认继承 Object 类)还要实现 Cloneable 这个 标记接口虽然它没有定义方法但要使用 clone() 方法就得实现它否则就会抛出 CloneNotSupportedException (不支持 clone() 方法)的异常。
5.2.3 Client ( 使用者 )
该角色负责 使用 用于复制现有实例来生成新实例的 方法。
6 原型模式的优缺点
优点
性能高使用原型模式复用的方式创建实例对象比使用构造器重新创建对象性能要高。流程简单原型模式可以简化创建的过程可以直接修改现有的对象实例的值达到复用的目的。具有动态性使用构造器创建对象的代码在运行期间时固定的而使用原型模式可以获取对象运行时的属性从而 动态地 创建出新的对象。
缺点
实现复杂必须重写对象的 clone() 方法且需要考虑 深拷贝 与 浅拷贝 的风险。克隆方法需要通盘考虑配备克隆方法需要对类的功能进行通盘考虑特别是对于已有的类可能需要修改其结构以支持克隆违背了 开闭原则。
7 原型模式的使用场景
对象的创建成本较高如果创建对象的过程比较复杂或耗时较长可以使用原型模式通过复制一个现有对象的属性和方法来创建新对象从而避免昂贵的创建过程。需要创建大量相似的对象如果需要创建大量相似的对象可以先创建一个原型对象然后通过复制原型对象来创建新对象从而提高对象创建的效率和性能。对象的修改频繁如果对象的属性需要经常变化而且每次变化都需要创建一个新的对象可以使用原型模式通过复制原型对象来创建新对象并修改其属性而不需要每次都重新创建新对象。隐藏对象的创建细节如果创建对象的细节比较复杂不希望客户端直接与创建对象的过程耦合可以使用原型模式客户端只需要通过复制一个已有对象来创建新对象而无需知道创建的细节。
8 总结
原型模式是一种非常有用的 创建型 设计模式它 通过复制已有的对象来创建新对象从而 提高了对象创建的效率和性能。然而在使用时需要注意 深浅拷贝问题 以及 克隆方法的实现细节以避免出现不必要的错误。