定义
Prototype模式是一种对象创建型模式,它采取复制原型对象的方法来创建对象的实例。使用Prototype模式创建的实例,具有与原型一样的数据。
特点
- 由原型对象自身创建目标对象。也就是说,对象创建这一动作发自原型对象本身。
- 目标对象是原型对象的一个克隆。也就是说,通过Prototype模式创建的对象,不仅仅与原型对象具有相同的结构,还与原型对象具有相同的值。
- 根据对象克隆深度层次的不同,有浅度克隆与深度克隆
应用场景
- 资源优化场景。
- 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
- 性能和安全要求的场景。
- 通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
- 一个对象多个修改者的场景。
- 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
- 在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与 Java 融为浑然一体,大家可以随手拿来使用。
缺点
- 配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
- 必须实现 Cloneable 接口
生活映射
相信熟悉java的朋友到这里已经了解原型模式了,在我们生活中有什么原型模式呢,其实编程来源于生活嘛,万物皆对象(多么牛的话),前段时间我看了一个电影,叫《我不是药神》,没有看过这部电影的朋友可以看一下(我在这里安利一波,很经典),其实在电影里面就有原型模式,瑞士的诺瓦医药公司投入巨大的资金、人力等开发出了一款能够抗击慢粒白血病的药物(这就是原型模式中的原型),而印度的一个制药公司只需要分析出药品中的材料,就可以轻松制造出相同功效的药物(原型模式中的克隆,较小的开销实现较大的效率),假药的制作(我指的是功效相同,但是医疗手册中没有的药)我认为就是生活中的原型模式。
实现代码
代码可在码云中下载(包名为e_prototype)
https://gitee.com/XiaoSa12138/java-models
浅度克隆(被克隆对象中只包含基本类型)
/**
* 被克隆的bean继承Cloneable接口,可以使用Object的clone方法克隆
*/
public class Person implements Cloneable {
private String name;
private int age;
private double height;
private List<String> friends;
//sets&gets
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", height=" + height + ", friends=" + friends + "]";
}
/**
* 克隆方法
*/
public Person getPerson() {
try {
return (Person) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
/**
* 测试类
*/
public class Main {
public static void main(String[] args) {
Person p1 = new Person();
p1.setName("张三");
p1.setAge(10);
p1.setHeight(110.1);
Person p2 = p1.getPerson();
p2.setName("李四");
System.out.println(p1);
System.out.println(p2);
}
}
深度克隆(被克隆对象中包含对象类型)
/**
* 被克隆的bean继承Cloneable接口,可以使用Object的clone方法克隆
*/
public class Person implements Cloneable {
private String name;
private int age;
private double height;
private List<String> friends;
//sets&gets
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", height=" + height + ", friends=" + friends + "]";
}
/**
* 克隆方法
* 由于对象中含有引用类型的属性,浅克隆不会克隆引用类型指向的对象,只会克隆对象的引用,此时原型对象与克隆对象的引用属性依然使用的同一个对象
* 因此,需要在克隆时将引用类型的属性再创建一遍,并复制数据,使与原型对象完全脱离,实现深度克隆
*/
public Person getPerson() {
try {
Person person = (Person) super.clone();
List<String> friends = new ArrayList<>();
for (String friend : this.friends) {
friends.add(friend);
}
person.setFriends(friends);
return person;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
/**
* 测试类
*/
public class Main {
public static void main(String[] args) {
Person p1 = new Person();
p1.setName("张三");
p1.setAge(10);
p1.setHeight(110.1);
List<String> friends = new ArrayList<>();
friends.add("黛玉晴雯子");
friends.add("木村躲债");
p1.setFriends(friends);
Person p2 = p1.getPerson();
p2.setName("李四");
System.out.println(p1);
System.out.println(p2);
friends.add("萧十一郎");
System.out.println(p1);
System.out.println(p2);
}
}