基本需求:
- 有一个Sheep类的对象,我们现在需要创建100个和该对象属性完全一致的对象
传统方式:
基本介绍:
-
创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用
-
实现方式:实现Cloneable接口,复写clone()方法或通过序列化,原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些"易变类"拥有稳定的接口
-
优缺点:
- 性能提高,逃避构造函数的约束
- 配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候
- 必须实现 Cloneable 接口
-
使用场景:
- 资源优化场景、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等
- 性能和安全要求的场景、通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式
- 一个对象多个修改者的场景、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用
- 在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者
-
UMl类图
-
代码实现
-
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Sheep implements Serializable,Cloneable {
private String name;
private int age;
// 默认的super.clone()实现的浅拷贝,即对于基本类型和字符串拷贝直接赋值,对于引用类型的直接拷贝的引用(并没有重新创建该内部的对象)
private Friend friend;
@Override
protected Object clone() throws CloneNotSupportedException {
// 如果没有实现Cloneable接口 调用该方法会抛出CloneNotSupportedException异常
return super.clone();
}
}
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Friend friend = new Friend("666");
Sheep sheep = new Sheep("zhangsan",23,friend);
// 使用默认clone方法 采用的是浅拷贝
Sheep sheep1 = (Sheep) sheep.clone();
Sheep sheep2 = (Sheep) sheep.clone();
System.out.println(sheep1.toString());
System.out.println(sheep2.toString());
// 结果是true 说明clone出来的sheep1和sheep2中引用的是同一Friend对象,并没有将Friend对象再克隆一份,是浅拷贝
// 深拷贝则是将Friend对象再克隆一份,sheep1和sheep2中引用的不是同一Friend对象 结果为false
System.out.println(sheep1.getFriend() == sheep2.getFriend());
}
}
spring源码:
浅拷贝和深拷贝:
注意事项:
- 创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率
- 不用重新初始化对象,而是动态地获得对象运行时的状态
- 如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码
- 在实现深克隆的时候可能需要比较复杂的代码
- 缺点:需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了ocp原则
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|