Spring中常见的设计模式——原型模式
1、原型模式应用场景
当遇到大量耗费劳动力的 get,set赋值场景时,如下:
public class SetGetParam {
public void setParam(UserDto userDto) {
User user = new User();
user.setAge(userDto.getAge());
//...
userDao.addUser(user);
}
}
原型模式(Prototype pattern)是指原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。原型模式主要适用于以下:
(1)类初始化消耗资源较多;
(2)使用new 生成一个对象需要非常繁琐的过程(数据准备访问权限等);
(3)构造函数比较复杂;
(4)在循环体中产生大量对象;
在spring中用到的原型模式有:scope="prototype" ,还有常用的JSON.parseObject()也是一种原型模式
2、浅克隆
创建具体需要克隆的类:
@Data
public class User {
private String name; private Integer age; private List<String> hobbies; public UserDto clone() {
UserDto dto = new UserDto();
dto.setAge(this.age);
dto.setName(this.name);
dto.setHobbies(this.hobbies);
return dto;
}
}
创建Client:
public class Client {
private User user;
public Client(User user) {
this.user = user;
}
public UserDto startClone(User user) {
return user.clone();
}
}
测试克隆,对比复制过来的值是否有自己的地址,还是用的原来的地址
public class PrototypeTest {
public static void main(String[] args) {
//创建具体需要克隆的对象
User user = new User();
user.setName("皮肤黝黑的小白");
user.setHobbies(new ArrayList<>());
System.out.println(user);
//创建Client对象,准备开始克隆
Client client = new Client(user);
UserDto dto = client.startClone(user);
System.out.println(dto);
System.out.println(user.getHobbies() == dto.getHobbies());
System.out.println(user.getName() == dto.getName());
}
}
结果:
User(name=皮肤黝黑的小白, age=null, hobbies=[])
UserDto(name=皮肤黝黑的小白, age=null, hobbies=[])
true
true
从测试结果可以看出:hobbies和name的内存地址是相同的,这说明我们并没有重新创建对象,这就是浅克隆。
3、深克隆
采用序列化反序列化克隆,实现深克隆,
@Data
public class UserDeepClone implements Cloneable {
private String name; private Integer age; private List<String> hobbies; @Override
protected Object clone() throws CloneNotSupportedException {
return this.deepClone();
} public UserDto deepClone() {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
UserDto dto = (UserDto) ois.readObject();
return dto;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
public class DeepCloneTest {
public static void main(String[] args) {
DeepCloneTest deepCloneTest = new DeepCloneTest();
UserDeepClone user = new UserDeepClone();
user.setName("皮肤黝黑的小白");
user.setHobbies(new ArrayList<>());
System.out.println(user);
UserDto dto = null;
try {
dto = (UserDto) deepCloneTest.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
System.out.println(dto);
System.out.println(user.getName() == dto.getName());
System.out.println(user.getHobbies() == dto.getHobbies());
}
}
4、克隆破坏单例
深克隆会破坏单例,其实防御方式很简单,单例类不要实现Cloneable接口即可。
5、ArrayList中clone()方法的源码
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
Spring中常见的设计模式——原型模式的更多相关文章
- Spring中常见的设计模式——代理模式
一.代理模式的应用场景 生活中的中介,黄牛,等一系列帮助甲方做事的行为,都是代理模式的体现.代理模式(Proxy Pattern)是指为题对象提供一种代理,以控制对这个对象的访问.代理对象在客户端和目 ...
- Spring中常见的设计模式——策略模式
策略模式(Strategy Pattern) 一.策略模式的应用场景 策略模式的应用场景如下: 系统中有很多类,而他们的区别仅仅在于行为不同. 一个系统需要动态的在集中算法中选择一种 二.用策略模式实 ...
- Spring中常见的设计模式——委派模式
一.委派模式的定义及应用场景 委派模式(Delegate Pattern)的基本作用是负责任务的调用和分配,跟代理模式很像,可以看做特殊情况下的静态的全权代理,但是代理模式注重过程,而委派模式注重结果 ...
- Spring中常见的设计模式——工厂模式
一.简单工厂模式 简单工厂模式(Simple Factory Pattern)由一个工厂对象决定创建哪一种产品类的实例,简单工厂模式适用于工厂类负责创建对象较少的情况,且客户端只需要传入工厂类的参数, ...
- Spring中常见的设计模式——模板模式
一.模板模式的应用场景 模板模式又叫模板方法模式(Template Method Pattern),指定义一个算法的骨架,并允许自雷为一个或者多个步骤提供实现.模板模式使得子类可以在不改变算法结果的情 ...
- Spring中常见的设计模式——适配器模式
一.适配器模式的应用场景 适配器模式(Adapter Pattern)是指将一个类的接口转换成用户期待的另一个接口,使原本接口不兼容的类可以一起工作,属于构造设计模式. 适配器适用于以下几种业务场景: ...
- 设计模式:JDK和Spring中常见的设计模式
设计模式 总结 类 工厂模式 封装创建过程,只对结果负责 BeanFactory.Calender 单例模式 全局唯一 ApplicationContext.Calender 原型模式 多重影分身之术 ...
- Spring中常见的设计模式——单例模式
一.单例模式的应用场景 单例模式(singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点.J2EE中的ServletContext,ServletCon ...
- spring 中常用的设计模式
一. Spring 中常见的设计模式 工厂模式 : BeanFactory 装饰器模式: BeanWrapper 代理模式: AopProxy 单例模式: ApplicationContext 委派模 ...
随机推荐
- 实用Linux控制台命令
实用Linux控制台命令 screen 例如用Xshell连接 服务器 screen -ls 列出当前用户所有的screen screen 回车直接创建新的screen screen -S scree ...
- Log4j slf4j 配置简单介绍
Log4j slf4j 配置简单介绍 先借鉴一篇很好的文章 为什么要使用SLF4J而不是Log4J import org.slf4j.Logger; import org.slf4j.LoggerFa ...
- 设计模式C++描述----11.组合(Composite)模式
一. 举例 这个例子是书上的,假设有一个公司的组结结构如下: 它的结构很像一棵树,其中人力资源部和财务部是没有子结点的,具体公司才有子结点. 而且最关健的是,它的每一层结构很相似. 代码实现如下: / ...
- 【Redis深度历险】那些年Redis的数据结构
[Redis深度历险]那些年Redis的数据结构 Redis端口号6379的来源 Redis的端口号是6379,但这个端口号并不是随机选择的,源于"MERZ",这个单词在手机当中的 ...
- Okhttp 请求流程梳理
最近在看 Okhttp 的源码.不得不说源码设计的很巧妙,从中能学到很多.其实网上关于 Okhttp 的文章已经很多了,自己也看了很多.但是俗话说得好,好记性不如烂笔头,当你动手的时候,你会发现你在看 ...
- 等距结点下的Newton插值多项式系数计算(向前差分)
插值多项式的牛顿法 1.为何需要牛顿法? 使用Lagrange插值法不具备继承性.当求好经过\(({x_0},{y_0})-({x_n},{y_n})\)共n+1个点的插值曲线时候,如果再增加一个 ...
- (八)golang--复杂类型之指针
首先我们要明确:(1)基本数据类型:变量存的就是值,也叫值类型: (2)获取变量的地址,用&,例如var num int,获取num的地址:&num: (3)指针类型:变量存的是一个地 ...
- [考试反思]0902NOIP模拟测试35:摆动
skyh/Mr.zkt214 cbx204 6个200 4个180 172 162 我:rank16,160 呃,可以看到这个分差.... 对了教练说了两句话需要记录一下: 1.不要因为一时情绪而作出 ...
- IDEA升级,提示"Connection Error Failed to prepare an update"
问题来源: 之前修改了IDEA的默认配置文件路径,然后升级新版本时就无法升级,提示"Failed to prepare an update Temp directory inside ins ...
- 决策树(上)-ID3、C4.5、CART
参考资料(要是对于本文的理解不够透彻,必须将以下博客认知阅读,方可全面了解决策树): 1.https://zhuanlan.zhihu.com/p/85731206 2.https://zhuanla ...