一、原型模式介绍
①定义:
是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
②优缺点:
优点:
- 性能提高。
- 逃避构造函数的约束。
缺点:
- 配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
- 必须实现 Cloneable 接口。
③角色
- 客户(Client)角色:客户类提出创建对象的请求;。
- 抽象原型(Prototype)角色:此角色定义了的具体原型类所需的实现的方法。也就是定义一个文件,说明一下它有被克隆复制的功能。
- 具体原型(Concrete Prototype)角色:实现抽象原型角色的克隆接口。就是我们的文件实现了可以被复制的功能。
④分类
浅拷贝:我们只拷贝对象中的基本数据类型(8种)和String,对于数组、容器、引用对象等都不会拷贝;
深拷贝:不仅能拷贝基本数据类型,还能拷贝那些数组、容器、引用对象等;
⑤注意点
- 克隆对象不会调用构造方法;
- 访问权限对原型模式无效,从内存中直接复制的,所以克隆起来也会直接无视;
- 使用场景:当我们的类初始化需要消耗很多的资源时,就可以使用原型模式,因为我们的克隆不会执行构造方法,避免了初始化占有的时间和空间。 一个对象被其她对象访问,并且能够修改时,访问权限都无效了,什么都能修改。
二、代码示例
@Data
@AllArgsConstructor
@ToString
public class Dog implements Cloneable {
private Integer id;
private String name;
private BigDecimal weight;
private Food food;
public Dog(Integer id, String name, BigDecimal weight) {
this.id = id;
this.name = name;
this.weight = weight;
}
//浅拷贝-实现一种
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
//深拷贝-实现一种
@Override
protected Object clone() throws CloneNotSupportedException {
Object o = super.clone();
Food food = ((Dog) o).getFood();
((Dog) o).setFood((Food) food.clone());
return o;
}
}
--------------------------------------------
@Data
@AllArgsConstructor
@ToString
public class Food implements Cloneable {
private String name;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
--------------------------------------------
public class Test {
//浅拷贝
@org.junit.Test
public void test1() throws CloneNotSupportedException {
Dog jack = new Dog(2, "jack", BigDecimal.TEN);
Dog tom = (Dog) jack.clone();
tom.setId(3);
tom.setName("tom");
tom.setWeight(BigDecimal.ONE);
System.out.println(jack);
System.out.println(tom);
}
//深拷贝
@org.junit.Test
public void test2() throws CloneNotSupportedException {
Dog jack = new Dog(2, "jack", BigDecimal.TEN);
jack.setFood(new Food("碎碎冰"));
Dog tom=(Dog) jack.clone();
tom.setId(3);
tom.setName("tom");
tom.setWeight(BigDecimal.ONE);
tom.getFood().setName("巧克力");
System.out.println(jack);
System.out.println(tom);
}
}