基本介绍
定义
原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
使用场景
一个对象需要提供给其他对象访问,而各个调用者都需要修改其值,可以利用原型模式赋值多个拷贝对象公其他调用者使用。
使用优点
减少了类对象创建时的资源消耗。通过原型模式,直接操作内存中的数据,对于一些复杂对象的创建,大大减少了资源的消耗。
实现方式
首先看一下代码
/**
*
* 原型模式
*
*/
public class Prototype implements Cloneable {
private String id;
private ArrayList names;
public Prototype(String id, ArrayList names) {
this.id= id;
this.names= names;
}
// 拷贝方法
@Override
publicObject clone() {
Prototype prototype =null;
try{
// 调用Object的clone() 拷贝对象
prototype = (Prototype)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
// 返回拷贝的实例对象
returnprototype ;
}
publicString getId() {
returnid;
}
public voidsetId(String id) {
this.id= id;
}
publicArrayList getNames() {
returnnames;
}
public voidsetNames(ArrayList names) {
this.names= names;
}
@Override
publicString toString() {
return"Prototype{"+
"id='"+id+'\''+
", names="+names+
'}';
}
}
从代码上看,实现方式分为两个步骤:
(1)实现Cloneable接口,该接口是一个空接口,没有任何需要实现的方法。
(2)重写clone()方法,该方法重写了Object的clone()方法。
在重写clone()方法内,直接调用了super.clone()获取了对象的实例。
注意
通过clone()获取的对象,不会调用该对象的构造方法。
使用方式
@Test
public voidtest_prototype(){
ArrayList names =newArrayList<>();
Prototype prototype =newPrototype("1",names);
// 拷贝对象
Prototype clone = (Prototype) prototype.clone();
System.out.println("********拷贝对象************");
System.out.println(clone);
// 对拷贝对象设置值
clone.getNames().add("Alex");
clone.setId("2");
// 看一下修改结果
System.out.println("********原对象************");
System.out.println(prototype);
System.out.println("********拷贝对象************");
System.out.println(clone);
}
使用方式很简单,直接调用prototype.clone()方法就获取到了拷贝对象。根据分析,拷贝对象修改数值不会影响到原对象,那么结果是这样的吗?
********拷贝对象************
Prototype{id='1', names=[]}
********原对象************
Prototype{id='1', names=[Alex]}
********拷贝对象************
Prototype{id='2', names=[Alex]}
通过对结果分析,发现id没有收到影响,但names确收到了影响。为什么呢?
如果对于方法传参,形参和实参能够理解的话,这个地方类似。拷贝拷贝的是他们的值,而names的值时一个地址,拷贝对象也是该地址,那么修改该地址的值,两者都会改变。那么这种拷贝称之为浅拷贝。
既然有浅拷贝,那么肯定有深拷贝:
只需要我们实现clone()方法的地方修改代码
// 拷贝方法
@Override
publicObject clone() {
Prototype prototype =null;
try{
// 调用Object的clone() 拷贝对象
prototype = (Prototype)super.clone();
// 一些集合类都默认实现了clone()方法
prototype.names = (ArrayList)this.names.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
// 返回拷贝的实例对象
returnprototype ;
}
添加了代码prototype.names = (ArrayList) this.names.clone();,幸运的是Java提供的大部分的容器类都实现了Cloneable接口。
看一下结果
********拷贝对象************
Prototype{id='1', names=[]}
********原对象************
Prototype{id='1', names=[]}
********拷贝对象************
Prototype{id='2', names=[Alex]}
在Android中的应用
在Android开发中,通常会在Application中保存全局的User对象,该对象在某些时候便于操作,如下所示
**
* 自定义Application
* Created by alex_mahao on2016/8/30.
*/
public classAppextendsApplication {
// 保存user对象
privateUseruser;
@Override
public voidonCreate() {
super.onCreate();
}
// 设置user对象
public voidsetUser(User user){
user =this.user;
}
publicUser getUser(){
returnuser;
}
}
而在业务中,可能会有一些修改User对象的操作,例如修改用户名,密码等,我们可以自己new一个对象,对对象进行必要的赋值之后,通过网络请求传输过去,那么现在我们可以通过clone的方式进行修改。
首先看一下User对象的定义
/**
* 自定义Application
* Created by alex_mahao on 2016/8/30.
*/
public classAppextendsApplication {
// 保存user对象
privateUseruser;
@Override
public voidonCreate() {
super.onCreate();
}
// 设置user对象
public voidsetUser(User user){
user =this.user;
}
}
那么在进行网络请求修改密码时:
User user = app.getUser().clone();
// post 请求
post(url,toJson(user),newCallback{
public voidonSuccess(){
// 成功的回调
app.setUser(user);
}
public voidonFail(){
// 失败的回调,不做任何操作
}
});