1.什么是原型模式
原型模式是一个创建型的模式。原型二字表明了改模式应该有一个样板实例,用户从这个样板对象中复制一个内部属性一致的对象,这个过程也就是我们称的“克隆”。被复制的实例就是我们所称的“原型”,这个原型是可定制的。原型模式多用于创建复杂的或者构造耗时的实例,因为这种情况下,复制一个已经存在的实例可使程序运行更高效。
2.原型模式应用场景
(1) 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等,通过原型拷贝避免这些消耗。
(2)通过new产生的一个对象需要非常繁琐的数据准备或者权限,这时可以使用原型模式。
(3)一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝。
Spring框架中的多例Prototype就是使用原型。
3.原型模式实现方式
原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype。Prototype类需要具备以下两个条件:
(1)实现Cloneable接口。在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。在java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常。
(2)重写Object类中的clone方法。Java中,所有类的父类都是Object类,Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用,因此Prototype类需要将clone方法的作用域修改为public类型。
4.代码实现
package com.designpattern.prototype;
import java.util.ArrayList;
/**
* @description: 原型类,书本类型,扮演的是ConcretePrototype角色,而Cloneable扮演Prototype角色
* @author: Codegitz
* @create: 2020-05-19 13:43
**/
public class Book extends Object implements Cloneable {
private String title;
private ArrayList<String> imgList = new ArrayList<>();
public Book(){
super();
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public ArrayList<String> getImgList() {
return imgList;
}
public void setImgList(ArrayList<String> imgList) {
this.imgList = imgList;
}
public void add(String name){
imgList.add(name);
}
/**
* 重写拷贝方法
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Book clone() throws CloneNotSupportedException {
try{
Book book = (Book) super.clone();
//深拷贝,开辟新的内存
// book.imgList = (ArrayList<String>) this.imgList.clone();
return book;
}catch (CloneNotSupportedException e){
e.printStackTrace();
}
return null;
}
public void showBook(){
System.out.println("=============start=================");
System.out.println("title: "+title);
for (String img : imgList){
System.out.println("img: "+img);
}
System.out.println("==============end=================");
}
}
测试代码:
package com.designpattern.prototype;
public class TestPrototype {
public static void main(String[] args) throws CloneNotSupportedException {
Book book1 = new Book();
book1.setTitle("book1");
book1.add("name1");
//先展示一下book1
book1.showBook();
//克隆book1的属性给book2
Book book2 = (Book)book1.clone();
book2.setTitle("book2");
//给book2增加属性
book2.add("name2");
//展示book2
book2.showBook();
//再展示book1
book1.showBook();
}
}
采用浅拷贝方式的运行结果:
=============start=================
title: book1
img: name1
==============end=================
=============start=================
title: book2
img: name1
img: name2
==============end=================
=============start=================
title: book1
img: name1
img: name2
==============end=================
采用深拷贝的运行结果:
=============start=================
title: book1
img: name1
==============end=================
=============start=================
title: book2
img: name1
img: name2
==============end=================
=============start=================
title: book1
img: name1
==============end=================
附完整代码,需要自取,顺便点个star。
5.原型模式的浅拷贝和深拷贝的区别
从上面的结果我们可以看到区别,浅拷贝出来的对象,如果是引用类型,如果进行了修改,那么原本的类型也会发生改变,如果是深拷贝,则不会出现这种情况。
浅拷贝–只是拷贝了基本类型的数据,而引用类型数据,拷贝后也是会发生引用,我们把这种拷贝叫做“浅拷贝”,换句话说,浅拷贝仅仅是指向被拷贝的内存地址,如果原地址中对象被改变了,那么浅拷贝出来的对象也会相应改变。
深拷贝–在计算机中开辟了一块新的内存地址用于存放拷贝的对象。