基本介紹
定義
原型模式(Prototype Pattern):用原型實例指定創(chuàng)建對象的種類颂斜,并通過拷貝這些原型創(chuàng)建新的對象碉输。
使用場景
一個對象需要提供給其他對象訪問秫筏,而各個調(diào)用者都需要修改其值隘冲,可以利用原型模式賦值多個拷貝對象公其他調(diào)用者使用抵赢。
使用優(yōu)點
減少了類對象創(chuàng)建時的資源消耗欺劳。通過原型模式,直接操作內(nèi)存中的數(shù)據(jù)铅鲤,對于一些復(fù)雜對象的創(chuàng)建划提,大大減少了資源的消耗。
實現(xiàn)方式
首先看一下代碼
/**
*
* 原型模式
*
*/
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{
// 調(diào)用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+
'}';
}
}
從代碼上看邢享,實現(xiàn)方式分為兩個步驟:
(1)實現(xiàn)Cloneable接口鹏往,該接口是一個空接口,沒有任何需要實現(xiàn)的方法骇塘。
(2)重寫clone()方法伊履,該方法重寫了Object的clone()方法。
在重寫clone()方法內(nèi)绪爸,直接調(diào)用了super.clone()獲取了對象的實例湾碎。
注意
通過clone()獲取的對象,不會調(diào)用該對象的構(gòu)造方法奠货。
使用方式
@Test
public voidtest_prototype(){
ArrayList names =newArrayList<>();
Prototype prototype =newPrototype("1",names);
// 拷貝對象
Prototype clone = (Prototype) prototype.clone();
System.out.println("********拷貝對象************");
System.out.println(clone);
// 對拷貝對象設(shè)置值
clone.getNames().add("Alex");
clone.setId("2");
// 看一下修改結(jié)果
System.out.println("********原對象************");
System.out.println(prototype);
System.out.println("********拷貝對象************");
System.out.println(clone);
}
使用方式很簡單介褥,直接調(diào)用prototype.clone()方法就獲取到了拷貝對象。根據(jù)分析递惋,拷貝對象修改數(shù)值不會影響到原對象柔滔,那么結(jié)果是這樣的嗎?
********拷貝對象************
Prototype{id='1', names=[]}
********原對象************
Prototype{id='1', names=[Alex]}
********拷貝對象************
Prototype{id='2', names=[Alex]}
通過對結(jié)果分析萍虽,發(fā)現(xiàn)id沒有收到影響睛廊,但names確收到了影響。為什么呢杉编?
如果對于方法傳參超全,形參和實參能夠理解的話,這個地方類似邓馒∷恢欤拷貝拷貝的是他們的值,而names的值時一個地址光酣,拷貝對象也是該地址疏遏,那么修改該地址的值,兩者都會改變。那么這種拷貝稱之為淺拷貝财异。
既然有淺拷貝倘零,那么肯定有深拷貝:
只需要我們實現(xiàn)clone()方法的地方修改代碼
// 拷貝方法
@Override
publicObject clone() {
Prototype prototype =null;
try{
// 調(diào)用Object的clone() 拷貝對象
prototype = (Prototype)super.clone();
// 一些集合類都默認(rèn)實現(xiàn)了clone()方法
prototype.names = (ArrayList)this.names.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
// 返回拷貝的實例對象
returnprototype ;
}
添加了代碼prototype.names = (ArrayList) this.names.clone();,幸運的是Java提供的大部分的容器類都實現(xiàn)了Cloneable接口戳寸。
看一下結(jié)果
********拷貝對象************
Prototype{id='1', names=[]}
********原對象************
Prototype{id='1', names=[]}
********拷貝對象************
Prototype{id='2', names=[Alex]}
在Android中的應(yīng)用
在Android開發(fā)中呈驶,通常會在Application中保存全局的User對象,該對象在某些時候便于操作庆揩,如下所示
**
*? 自定義Application
* Created by alex_mahao on2016/8/30.
*/
public classAppextendsApplication {
// 保存user對象
privateUseruser;
@Override
public voidonCreate() {
super.onCreate();
}
// 設(shè)置user對象
public voidsetUser(User user){
user =this.user;
}
publicUser getUser(){
returnuser;
}
}
而在業(yè)務(wù)中俐东,可能會有一些修改User對象的操作,例如修改用戶名订晌,密碼等,我們可以自己new一個對象蚌吸,對對象進(jìn)行必要的賦值之后锈拨,通過網(wǎng)絡(luò)請求傳輸過去,那么現(xiàn)在我們可以通過clone的方式進(jìn)行修改羹唠。
首先看一下User對象的定義
/**
*? 自定義Application
* Created by alex_mahao on 2016/8/30.
*/
public classAppextendsApplication {
// 保存user對象
privateUseruser;
@Override
public voidonCreate() {
super.onCreate();
}
// 設(shè)置user對象
public voidsetUser(User user){
user =this.user;
}
}
那么在進(jìn)行網(wǎng)絡(luò)請求修改密碼時:
User user = app.getUser().clone();
// post 請求
post(url,toJson(user),newCallback{
public voidonSuccess(){
// 成功的回調(diào)
app.setUser(user);
}
public voidonFail(){
// 失敗的回調(diào)奕枢,不做任何操作
}
});