原型模式 java 深浅_Java描述设计模式(05):原型模式

一、原型模式简介

1、基础概念

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

2、模式结构

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

3、代码实现

1)、UML关系图

11a3c2166861ef38901a6e8a18245b96.png

Java描述设计模式(05):原型模式

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、配置文件

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() {

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

码云地址:知了一笑

https://gitee.com/cicadasmile

fb40ee901ad56b322ad90ac8698c296d.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值