结构型设计模式——原型模式

编程入门 行业动态 更新时间:2024-10-09 23:14:53

结构型设计<a href=https://www.elefans.com/category/jswz/34/1771241.html style=模式——原型模式"/>

结构型设计模式——原型模式

摘要

 本文主要分析设计模式 - 原型模式(Prototype),使用原型实例指定要创建对象的类型,通过复制这个原型来创建新对象。

一、原型模式意图

使用原型实例指定要创建对象的类型,通过复制这个原型来创建新对象。原型模式(Prototype)是一种创建型设计模式, 使你能够复制已有对象, 而又无需使代码依赖它们所属的类。

原型模式主要用于对象的复制,它的核心是就是类图中的原型类 Prototype。Prototype 类需要具备以下两个条件:

  • 实现 Cloneable 接口。在 java 语言有一个 Cloneable 接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用 clone 方法。在 java 虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出 CloneNotSupportedException 异常。
  • 重写 Object 类中的 clone 方法。Java 中,所有类的父类都是 Object 类,Object 类中有一个 clone 方法,作用是返回对象的一个拷贝,但是其作用域 protected 类型的,一般的类无法调用,因此,Prototype 类需要将 clone 方法的作用域修改为 public 类型。

二、原型模式场景

  • 如果你需要复制一些对象, 同时又希望代码独立于这些对象所属的具体类, 可以使用原型模式。
  • 如果子类的区别仅在于其对象的初始化方式, 那么你可以使用该模式来减少子类的数量。 别人创建这些子类的目的可能是为了创建特定类型的对象。

三、原型模式类图

四、原型模式实现

public abstract class Prototype {abstract Prototype myClone();
}
public class ConcretePrototype extends Prototype {private String filed;public ConcretePrototype(String filed) {this.filed = filed;}@OverridePrototype myClone() {return new ConcretePrototype(filed);}@Overridepublic String toString() {return filed;}
}
public class Client {public static void main(String[] args) {Prototype prototype = new ConcretePrototype("abc");Prototype clone = prototype.myClone();System.out.println(clone.toString());}
}

五、原型模式开源示例

Spring 框架中,创建ApplicationContext时,使用的getBean方法中使用到了原型模式

六、浅拷贝与深拷贝

5.1 浅拷贝原理

  • 对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象
  • 对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值
  • 前面我们克隆羊就是浅拷贝
  • 浅拷贝是使用默认的 clone 方法来实现:sheep=(Sheep)super.clone();

5.2 深拷贝原理

  • 复制对象的所有基本数据类型的成员变量值
  • 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象进行拷贝
  • 深拷贝实现方式 1:重写clone方法来实现深拷贝
  • 深拷贝实现方式 2:通过对象序列化实现深拷贝
package com.zhuangxiaoyan.designpattern.clonemodel;import org.junit.Test;
import java.io.*;class DeepClonableTarget implements Serializable, Cloneable {private String cloneName;private String cloneClass;public DeepClonableTarget(String cloneName, String cloneClass) {this.cloneName = cloneName;this.cloneClass = cloneClass;}public String getCloneName() {return cloneName;}public void setCloneName(String cloneName) {this.cloneName = cloneName;}public String getCloneClass() {return cloneClass;}public void setCloneClass(String cloneClass) {this.cloneClass = cloneClass;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}/*** @description 重写 clone 方法来实现深拷贝* @param: null* @date: 2022/3/27 9:48* @return:* @author: xjl
*/
class DeepPrototype implements Serializable, Cloneable {private String name;private DeepClonableTarget deepClonableTarget;public DeepPrototype() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public DeepClonableTarget getDeepClonableTarget() {return deepClonableTarget;}public void setDeepClonableTarget(DeepClonableTarget deepClonableTarget) {this.deepClonableTarget = deepClonableTarget;}@Overrideprotected Object clone() throws CloneNotSupportedException {//基本数据类型拷贝Object object = super.clone();//引用类型拷贝DeepPrototype deepPrototype = (DeepPrototype) object;deepPrototype.deepClonableTarget = (DeepClonableTarget) deepClonableTarget.clone();return object;}
}/*** @description 深拷贝方式 通过对象序列化实现深拷贝* @param: null* @date: 2022/3/27 9:41* @return:* @author: xjl*/
class DeepPrototypeV2 implements Serializable, Cloneable {private String name;private DeepClonableTarget deepClonableTarget;public DeepPrototypeV2() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public DeepClonableTarget getDeepClonableTarget() {return deepClonableTarget;}public void setDeepClonableTarget(DeepClonableTarget deepClonableTarget) {this.deepClonableTarget = deepClonableTarget;}/*** @description 通过对象序列化实现深拷贝* @param:* @date: 2022/3/27 9:55* @return: com.zhuangxiaoyan.designpattern.clonemodel.DeepPrototype* @author: xjl*/public DeepPrototypeV2 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);return (DeepPrototypeV2) ois.readObject();} catch (Exception e) {e.printStackTrace();return null;} finally {try {if (ois != null) {ois.close();}if (bis != null) {bis.close();}if (oos != null) {oos.close();}if (bos != null) {bos.close();}} catch (IOException e) {e.printStackTrace();}}}
}/*** @Classname DeepTestDemo* @Description* @Date 2022/3/27 9:38* @Created by xjl*/
public class DeepTestDemo {@Testpublic void testv1() throws CloneNotSupportedException {DeepPrototype prototype = new DeepPrototype();prototype.setName("庄小焱");prototype.setDeepClonableTarget(new DeepClonableTarget("及时雨", "及时雨的类"));DeepPrototype clone1 = (DeepPrototype) prototype.clone();DeepPrototype clone2 = (DeepPrototype) prototype.clone();DeepPrototype clone3 = (DeepPrototype) prototype.clone();DeepPrototype clone4 = (DeepPrototype) prototype.clone();DeepPrototype clone5 = (DeepPrototype) prototype.clone();System.out.println(prototype.getName() + ", " + prototype.getDeepClonableTarget().hashCode()); // 庄小焱, 1554874502System.out.println(clone1.getName() + ", " + clone1.getDeepClonableTarget().hashCode()); // 庄小焱, 1846274136System.out.println(clone2.getName() + ", " + clone2.getDeepClonableTarget().hashCode()); // 庄小焱, 1639705018System.out.println(clone3.getName() + ", " + clone3.getDeepClonableTarget().hashCode()); // 庄小焱, 1627674070System.out.println(clone4.getName() + ", " + clone4.getDeepClonableTarget().hashCode()); // 庄小焱, 1360875712System.out.println(clone5.getName() + ", " + clone5.getDeepClonableTarget().hashCode()); // 庄小焱, 1625635731}@Testpublic void testv2() throws CloneNotSupportedException {DeepPrototypeV2 prototypev2 = new DeepPrototypeV2();prototypev2.setName("庄小焱");prototypev2.setDeepClonableTarget(new DeepClonableTarget("zhuangxiaoyan", "yatou"));DeepPrototypeV2 clone1 = prototypev2.deepClone();DeepPrototypeV2 clone2 = prototypev2.deepClone();DeepPrototypeV2 clone3 = prototypev2.deepClone();DeepPrototypeV2 clone4 = prototypev2.deepClone();DeepPrototypeV2 clone5 = prototypev2.deepClone();System.out.println(prototypev2.getName() + ", " + prototypev2.getDeepClonableTarget().hashCode()); // 庄小焱,644117698System.out.println(clone1.getName() + ", " + clone1.getDeepClonableTarget().hashCode());           // 庄小焱, 317574433System.out.println(clone2.getName() + ", " + clone2.getDeepClonableTarget().hashCode());           // 庄小焱, 885284298System.out.println(clone3.getName() + ", " + clone3.getDeepClonableTarget().hashCode());           // 庄小焱, 1389133897System.out.println(clone4.getName() + ", " + clone4.getDeepClonableTarget().hashCode());           // 庄小焱, 1534030866System.out.println(clone5.getName() + ", " + clone5.getDeepClonableTarget().hashCode());           // 庄小焱, 664223387}
}

方式1和方式2对比

  • 在对象引用类型的成员属性较少时,方式 1 简单;在对象引用类型的成员属性较多时,方式 2 简单
  • 在对象引用类型的成员属性经常发生变化时,方式 1 需要同步修改,方式 2 不用修改
  • 推荐使用方式 2:耦合性低、可维护性强、扩展性高

注意事项和细节

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

博文参考

设计模式之原型模式 | DESIGN

创建型 - 原型模式(Prototype) | Java 全栈知识体系

更多推荐

结构型设计模式——原型模式

本文发布于:2024-03-14 09:29:34,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1736173.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:模式   原型   结构

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!