原型二字说明了该模式应该有一个样板实例,用户从这个样板对象复制(克隆)出一个内部属性一致的对象。被复制的实例就是原型。如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同),在这种情况下,我们可以利用对已有对象(原型)进行复制(或者叫拷贝)的方式来创建新对象,以达到节省创建时间的目的。这种基于原型来创建对象的方式就叫作原型设计模式(Prototype Design Pattern),简称原型模式。
1,类初始化需要很消耗资源,通过原型复制创建对象,可以避免这些资源消耗;
2,通过new创建一个对象需要很繁琐的数据准备,可通过原型模式;
3,一个类的不同对象之间差别不大,大部分字段都相同;
对于熟悉 JavaScript 语言的前端程序员来说,原型模式是一种比较常用的开发模式。这是因为,有别于 Java、C++ 等基于类的面向对象编程语言,JavaScript 是一种基于原型的面向对象编程语言。在Java语言中,最简单的实现就是调用的clone()方法;
案例:
原型
Book.class为原型,复制出更多的Book对象;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
public class Book implements Cloneable{
private String name;
private ArrayList mImages = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List getImages() {
return mImages;
}
public void setImage(String image) {
this.mImages.add(image);
}
public void showConten() {
System.out.println("**************** Start **************");
System.out.println("name: "+ this.name);
for (String img : mImages) {
System.out.println("image name: " + img);
}
System.out.println("**************** End **************");
}
@NonNull
@Override
protected Book clone() {
try {
Book book = (Book) super.clone();
book.name = this.name;
book.mImages = this.mImages;
return book;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
复制对象
public class CloneBook {
public static void main(String[] args) {
Book book = new Book();
book.setName("活法");
book.setImage("图1");
book.setImage("图2");
book.showConten();
Book book1 = book.clone();
book1.setName("Android");
book1.showConten();
book.showConten();
}
}
运行:
**************** Start **************
name: 活法
image name: 图1
image name: 图2
**************** End **************
**************** Start **************
name: Android
image name: 图1
image name: 图2
**************** End **************
**************** Start **************
name: 活法
image name: 图1
image name: 图2
**************** End **************
原型模式有两种实现方法,深拷贝和浅拷贝。不管浅拷贝还是深拷贝都是原型模式的实现方式;
浅拷贝:浅拷贝只会复制对象中基本数据类型数据和引用对象的内存地址,不会递归地复制引用对象,以及引用对象的引用对象;
上面的Book对象的拷贝就是浅拷贝,不信可以试试,代码如下
public class CloneBook {
public static void main(String[] args) {
Book book = new Book();
book.setName("活法");
book.setImage("图1");
book.setImage("图2");
book.showConten();
Book book1 = book.clone();
book1.setName("Android");
book1.setImage("图3");//修改引用对象的数据
book1.showConten();
book.showConten();
}
}
运行结果:
**************** Start **************
name: 活法
image name: 图1
image name: 图2
**************** End **************
**************** Start **************
name: Android
image name: 图1
image name: 图2
image name: 图3
**************** End **************
**************** Start **************
name: 活法
image name: 图1
image name: 图2
image name: 图3
**************** End **************
可以看出拷贝的对象book1修改了原型中的引用对象的数据(mImages),结果book对象中的引用对象的数据也改变了;book和book1同时指向mImages的同一个对象地址;
深拷贝:深拷贝得到的是一份完完全全独立的对象。
修改Book类中的clone方法
@NonNull
@Override
protected Book clone() {
try {
Book book = (Book) super.clone();
book.name = this.name;
book.mImages = (ArrayList) this.mImages.clone();
return book;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
重新运行如下代码
public class CloneBook {
public static void main(String[] args) {
Book book = new Book();
book.setName("活法");
book.setImage("图1");
book.setImage("图2");
book.showConten();
Book book1 = book.clone();
book1.setName("Android");
book1.setImage("图3");//修改引用对象的数据
book1.showConten();
book.showConten();
}
}
结果:book1修改了引用类型对象中的数据,对book没有任何影响;这就是深拷贝;
**************** Start **************
name: 活法
image name: 图1
image name: 图2
**************** End **************
**************** Start **************
name: Android
image name: 图1
image name: 图2
image name: 图3
**************** End **************
**************** Start **************
name: 活法
image name: 图1
image name: 图2
**************** End **************