设计模式源码git地址:design-pattern-src: 设计模式源码 (gitee.com)

  1. 什么是原型模式
  2. 使用场景
  3. 常见应用场景
  4. 什么是浅拷贝?
  5. 什么是深拷贝?
  6. 两种拷贝方式怎么实现?

什么是原型模式

原型模式就是去克隆对象,又涉及到创建对象了,为创建者模式

使用场景

1、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等,原型可以简化创建过程,提高创建效率

2、需要对对象中的部分属性进行修改,而其他属性不需要改变

常见应用场景

spring中的bean对象创建

1
<bean id="hi" class="com.test.Hi" init-method="init" scope="prototype">

其方法实现(摘取部分)来源于抽象类AbstractBeanFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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()) {
var12 = 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 {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ��" + beanName + "'");
}

Scope scope = (Scope)this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}

克隆对象就分为浅拷贝和深拷贝两种

什么是浅拷贝?

img

基本类型的值会复制一份开辟一个新空间,而引用类型则共用一个地址,这就表示如果修改数组中的一个值,另一个对象也会受到影响

什么是深拷贝?

基本类型与引用类型都会开辟一个空间,互相之间不受影响

实现方式

浅拷贝

实现cloneable接口,告诉jvm此类被标记,可以使用克隆方法

1
2
3
A a = new A();
A clone = (A) a.clone();
System.out.println(clone);

夺命三连问

1、克隆是否调用构造器方法?

不会,clone方法直接复制内存中的二进制,效率高

2、克隆出的对象和之前的是否一致?

不一致

3、改变克隆对象的值,原对象是否会变?

基本类型不变,引用类型随之改变

深拷贝

实现Serializable,Cloneable两个接口

方式一:在本方法内重写clone方法

1
2
3
4
5
6
7
8
9
@Override
protected Object clone() throws CloneNotSupportedException {
//全部克隆
Object deep = super.clone();
Deep deep1 = (Deep) deep;
//对象引用类型克隆
deep1.cloneArr = cloneArr.clone();
return deep1;
}

写起来方便,不好扩展

方式二:通过序列化的方式(推荐)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
protected Deep getDeep(){
//创建流对象
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
Deep deep = null;

try {
//写入
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this);

//读出
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
deep = (Deep) ois.readObject();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bis.close();
bos.close();
ois.close();
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return deep;
}

测试方法

1
2
3
4
5
6
7
8
9
10
11
12
13
//测试方式1
Deep deep1 = new Deep();
Deep deep2 = (Deep) deep1.clone();
deep1.cloneArr[0] = "peed";
System.out.println(deep1.cloneArr[0]);
System.out.println(deep2.cloneArr[0]);

//测试方式2
Deep deep3 = new Deep();
Deep deep4 = deep3.getDeep();
deep3.cloneArr[0] = "pig";
System.out.println(deep3.cloneArr[0]);
System.out.println(deep4.cloneArr[0]);

结果

1
2
3
4
5
6
方式一
peed
deep
方式二
pig
deep