本文源码:GitHub·点这里 || GitEE·点这里

一、原型模式简介

1、基础概念

原型模式属于对象的创建模式。通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象。

2、模式结构

原型模式要求对象实现一个可以“克隆”自身的接口,这样就可以通过复制一个实例对象本身来创建一个新的实例。这样一来,通过原型实例创建新的对象,就不再需要关心这个实例本身的类型,只要实现了克隆自身的方法,就可以通过这个方法来获取新的对象,而无须再去通过new来创建。

3、代码实现

1)、UML关系图



2)、核心角色

这种形式涉及到三个角色:

1)、客户(Client)角色:客户类提出创建对象的请求。

2)、抽象原型(Prototype)角色:这是一个抽象角色,通常由一个Java接口或Java抽象类实现。此角色给出所有的具体原型类所需的接口。

3)、具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口。

3)、基于JDK源码实现

/**
* 基于JDK源码方式实现原型模式
*/
public class C01_Property {
public static void main(String[] args) {
Product product = new Product("机械键盘","白色",100.00) ;
Product product1 = (Product) product.clone();
Product product2 = (Product) product.clone();
System.out.println(product1);
System.out.println(product2);
System.out.println(product1==product2); // false
}
}
class Product implements Cloneable {
private String name ;
private String color ;
private Double price ;
public Product(String name, String color, Double price) {
this.name = name;
this.color = color;
this.price = price;
}
@Override
public String toString() {
return "Product{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", price=" + price +
'}';
}
@Override
protected Object clone() {
Product product = null ;
try{
product = (Product)super.clone() ;
} catch (Exception e){
e.printStackTrace();
}
return product ;
}
// 省略GET和SET方法
}

二、Spring框架应用

1、配置文件

<!-- 多例Bean -->
<bean id="sheep01" class="com.model.design.spring.node05.property.Sheep" scope="prototype" />
<!-- 单例Bean 默认: scope="singleton" -->
<bean id="sheep02" class="com.model.design.spring.node05.property.Sheep"/>

2、测试代码块

@Test
public void test01 (){
ApplicationContext context01 = new ClassPathXmlApplicationContext(
"/spring/spring-property.xml");
// 原型模式
Sheep sheep1 = (Sheep)context01.getBean("sheep01") ;
Sheep sheep2 = (Sheep)context01.getBean("sheep01") ;
System.out.println(sheep1==sheep2); // false
// 单例模式
Sheep sheep3 = (Sheep)context01.getBean("sheep02") ;
Sheep sheep4 = (Sheep)context01.getBean("sheep02") ;
System.out.println(sheep3==sheep4); // true
}

3、核心源码

  • 所在类:org.springframework.beans.factory.support.AbstractBeanFactory
  • 所在方法:doGetBean

1)、执行流程

if (mbd.isSingleton()) {
sharedInstance = this.getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
try {
return AbstractBeanFactory.this.createBean(beanName, mbd, args);
} catch (BeansException var2) {
AbstractBeanFactory.this.destroySingleton(beanName);
throw var2;
}
}
});
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);
}

2)、单例多例判断

所以默认就是单例模式,指定[scope="prototype"]就是原型模式。

public boolean isSingleton() {
return "singleton".equals(this.scope) || "".equals(this.scope);
}
public boolean isPrototype() {
return "prototype".equals(this.scope);
}

三、深浅拷贝

1、浅拷贝

  1. 数据类型是基本数据类型、String类型的成员变量,浅拷贝直接进行值传递,也就是将该属性值复制一份给新的对象。
  2. 数据类型是引用数据类型的成员变量,比如说成员变量是数组、类的对象等,浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。实际上两个对象的成员变量都指向同一个实例。修改其中一个对象属性会影响到另一个对象的属性。
  3. 浅拷贝是使用默认的 clone()方法来实现。

2、深拷贝

1)、概念描述

除了浅拷贝要拷贝的值外,还负责拷贝引用类型的数据。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象,这种对被引用到的对象的复制叫做间接复制。

2)、源代码实现

序列化实现深度克隆

对象写到流里的过程是序列化(Serialization)过程;而把对象从流中读出来的过程则叫反序列化(Deserialization)过程。应当指出的是,写到流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。

在Java语言里深度克隆一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的拷贝)写到一个流里(序列化),再从流里读回来(反序列化),便可以重建对象。

/**
* 深拷贝和浅拷贝对比案例
*/
public class C02_DeepClone {
public static void main(String[] args) throws Exception {
Dog dog = new Dog("Tom") ;
Dog dog1 = (Dog)dog.clone() ;
Dog dog2 = (Dog)dog.clone() ;
// dog1:1639622804;dog2:1639622804
System.out.println("dog1:"+dog1.cat.hashCode()+";dog2:"+dog2.cat.hashCode());
Dog dog3 = (Dog)dog.deepClone() ;
Dog dog4 = (Dog)dog.deepClone() ;
// dog3:1937348256;dog4:1641808846
System.out.println("dog3:"+dog3.cat.hashCode()+";dog4:"+dog4.cat.hashCode());
}
} class Cat implements Serializable {
public String name ;
public Cat (String name){
this.name = name ;
}
}
class Dog implements Cloneable,Serializable {
public String name ;
public Cat cat ;
public Dog (String name){
this.name = name ;
this.cat = new Cat("Kit") ;
}
@Override
protected Object clone() {
Dog dog = null ;
try{
dog = (Dog)super.clone() ;
} catch (Exception e){
e.printStackTrace();
}
return dog ;
}
public Object deepClone() throws IOException, ClassNotFoundException{
//将对象写到流里面:序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//从流里面读出对象:反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
}

四、优缺点总结

1、优点总结

原型模式允许在运行时动态改变具体的实现类型。原型模式可以在运行期间,由客户来注册符合原型接口的实现类型,也可以动态地改变具体的实现类型,看起来接口没有任何变化,但其实运行的已经是另外一个类实例了。因为克隆一个原型就类似于实例化一个类。

2、缺点总结

原型模式最主要的缺点是每一个类都必须配备一个克隆方法。配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类来说不是很难,而对于已经有的类不一定很容易,特别是当一个类引用不支持序列化的间接对象,或者引用含有循环结构的时候。

五、源代码地址

GitHub·地址
https://github.com/cicadasmile/model-arithmetic-parent
GitEE·地址
https://gitee.com/cicadasmile/model-arithmetic-parent

Java描述设计模式(05):原型模式的更多相关文章

  1. GoLang设计模式05 - 原型模式

    原型模式也是一种创建型模式,它可以帮助我们优雅地创建对象的拷贝.在这种设计模式里面,将克隆某个对象的职责交给了要被克隆的这个对象.被克隆的对象需要提供一个clone()方法.通过这个方法可以返回该对象 ...

  2. JAVA 设计模式之原型模式

    目录 JAVA 设计模式之原型模式 简介 Java实现 1.浅拷贝 2.深拷贝 优缺点说明 1.优点 2.缺点 JAVA 设计模式之原型模式 简介 原型模式是六种创建型设计模式之一,主要应用于创建相同 ...

  3. java设计模式4——原型模式

    java设计模式4--原型模式 1.写在前面 本节内容与C++语言的复制构造函数.浅拷贝.深拷贝极为相似,因此建议学习者可以先了解C++的该部分的相关知识,或者学习完本节内容后,也去了解C++的相应内 ...

  4. 设计模式_11_原型模式(prototype)深拷贝、浅拷贝

    设计模式_11_原型模式(prototype) 浅拷贝: package designPatternOf23; /** * 定义:用原型实例,指定创建对象的种类,并通过拷贝这些原型创建新的对象 * P ...

  5. 设计模式之 原型模式详解(clone方法源码的简单剖析)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 原型模式算是JAVA中最简单 ...

  6. C# Json反序列化 C# 实现表单的自动化测试<通过程序控制一个网页> 验证码处理类:UnCodebase.cs + BauDuAi 读取验证码的值(并非好的解决方案) 大话设计模式:原型模式 C# 深浅复制 MemberwiseClone

    C# Json反序列化   Json反序列化有两种方式[本人],一种是生成实体的,方便处理大量数据,复杂度稍高,一种是用匿名类写,方便读取数据,较为简单. 使用了Newtonsoft.Json,可以自 ...

  7. GOF23设计模式之原型模式

    GOF23设计模式之原型模式 1)通过 new 产生一个对象需要飞船繁琐的数据准备或访问权限,则可以使用原型模式. 2)就算 java 中的克隆技术,以某个对象为原型,复制出新的对象.显然,新的对象具 ...

  8. C#设计模式(6)——原型模式(Prototype Pattern)

    一.引言 在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创建这样的类实例,这未免会增加创建类的复杂度和耗费更多的内存空间,因为这样在 ...

  9. 乐在其中设计模式(C#) - 原型模式(Prototype Pattern)

    原文:乐在其中设计模式(C#) - 原型模式(Prototype Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 原型模式(Prototype Pattern) 作者:weba ...

随机推荐

  1. ueEditor第一次赋值失败

    var ue=null; //在初始化富文本的地方 if (ue == null) { ue = new baidu.editor.ui.Editor(); ue.render('inspection ...

  2. SpringBoot整合axis1.4后,@Autowired注入失败,使用工具类注入

    问题描述: 费劲心思搭建好webservices服务端后,没想到客户端调用失败,查看日志文件,发现报空指针异常,debug代码后,发现sql查询的值都是null.通常情况下,我们将Dao注入Servi ...

  3. Java String indexOf()方法

    public class Test { public static void main(String[] args) { String s = "xXccxxxXX"; // 从头 ...

  4. 两个变量值交换的方法总结(js,python)

    方法一: 临时变量法 <script> var num1 = 10; var num2 = 20; var temp;//定义临时变量 temp = num1; num1 = num2; ...

  5. SpringBoot集成Swagger2在线文档

    目录 SpringBoot集成Swagger2在线文档 前言 集成SpringBoot 登录接口文档示例 代码 效果 注解说明 总结 SpringBoot集成Swagger2在线文档 前言 不得不说, ...

  6. 从KafkaConsumer看看Kafka(一)

      Kafka的消息模型为发布订阅模型,消息生产者将消息发布到主题(topic)中,一个或多个消费者订阅(消费)该主题消息并消费,此模型中发布到topic中的消息会被所有消费者所订阅到,先介绍Kafk ...

  7. 剑指offer-36:数组中的逆序对

    参考:1. https://www.geeksforgeeks.org/merge-sort/ 2.<剑指Offer:名企面试官精讲典型编程题> 题目描述 在数组中的两个数字,如果前面一个 ...

  8. git 版本检出checkout的方法笔记

    想检出指定版本,比如回退版本,将代码检出到老代码 git checkout 版本号 git reflog git checkout  标签名 1.git log 查看版本信息,复制版本号,执行git ...

  9. 在IIS中部署.net core应用

    在IIS中部署 .NET Core应用 对于熟悉IIS的程序员来说,将 .NET Core Web应用部署在IIS中,无疑是方便统一管理的事情.网上给出很多如何在IIS中部署 .NET Core 应用 ...

  10. C# 从字符串中提取指定字符类型的内容

    从一段字符串中,提取中文.英文.数字 中文字符30Margin中文字符40HorizontalAlignment 正则表达式: /// <summary> /// 英文字母与数字 /// ...