創(chuàng)建和銷(xiāo)毀對(duì)象
重點(diǎn)關(guān)注對(duì)象的創(chuàng)建和銷(xiāo)毀:什么時(shí)候、如何創(chuàng)建對(duì)象,什么時(shí)候、什么條件下應(yīng)該避免創(chuàng)建對(duì)象,如何保證對(duì)象在合適的方式下被銷(xiāo)毀,如何在銷(xiāo)毀對(duì)象之前操作一些必須的清理行為。
嘗試用靜態(tài)工廠方法代替構(gòu)造器
如果一個(gè)
client
要實(shí)例化一個(gè)對(duì)象來(lái)使用,傻
b
都知道應(yīng)該先調(diào)用類(lèi)的構(gòu)造器來(lái)
new
一個(gè)對(duì)象,之后再調(diào)用相應(yīng)的方法。除了這個(gè)方式,
Java Effective
還建議了另一種方法:用靜態(tài)工廠方法來(lái)提供一個(gè)類(lèi)的實(shí)例。以下的例子不反映兩者的優(yōu)劣,只是反映兩者在代碼實(shí)現(xiàn)上的不同,優(yōu)劣之后再談:
假設(shè)咱們要一個(gè)顏色為黑色、長(zhǎng)度為
50cm
的錘子,自然就用構(gòu)造器創(chuàng)建一個(gè)
Hammer myHammer =? new Hammer(Color.BLACK, 50);
而用靜態(tài)工廠方法來(lái)實(shí)例化一個(gè)對(duì)象,如下
Hammer myHammer = Hammer.factory(Color.BLACK,50);
也可以用專(zhuān)門(mén)的一個(gè)工廠類(lèi)來(lái)實(shí)例化
Hammer myHammer = Toolkit.factory(“Hammer”, Color.BLACK,50);??
單純從上面的代碼上看,真的只有傻
b
才會(huì)選擇靜態(tài)工廠的方法,完全就是多此一舉,直接
new
又快又爽,搞這么麻煩做莫斯(武漢話“什么”的意思)?
別急,別急,你急個(gè)莫
b
(武漢粗話:基本就是“你急個(gè)毛”的意思)?
下面就說(shuō)說(shuō)用靜態(tài)工廠代替構(gòu)造器的好處(
advantage
)和不好處(
disadvantage
)。
第一個(gè)好處,講你都不信,行家們認(rèn)為,構(gòu)造器有一個(gè)不好的地方就是:這個(gè)方法的簽名(
signture
)太固定了。
構(gòu)造器的名字是固定的,生個(gè)
Hammer
,構(gòu)造器的名字就是
Hammer
(……),唯一能變化的地方就是參數(shù),假設(shè)我的這個(gè)錘子有兩個(gè)很變態(tài)的構(gòu)造需要:
1
:第一個(gè)參數(shù)是顏色(
Color
型),第二個(gè)參數(shù)是錘子頭的重量(
int
型)。
Hammer
(
Color c, int kg
)
{
//remainder omited
}
2
:第一個(gè)參數(shù)是顏色(
Color
型),第二個(gè)參數(shù)是錘子的長(zhǎng)度(
int
型)。
Hammer
(
Color c, int cm
)
{
//remainder omited
}
感覺(jué)滿足需要了,但是細(xì)心一看,完了,構(gòu)造器的參數(shù)列表類(lèi)型重復(fù)了,肯定編譯通不過(guò),這是面向?qū)ο髽?gòu)造器天生的缺陷——唯一的變化就是參數(shù),參數(shù)都分辨不了,就真的分辨不了。
而另外就算參數(shù)能分辨的了,構(gòu)造器一多,它的參數(shù)一多,您根本就不知道每個(gè)參數(shù)是用來(lái)干什么的,只能去查閱文檔,在您已經(jīng)眼花繚亂的時(shí)候再去查文檔,一個(gè)一個(gè)的對(duì),折磨人的活。
這個(gè)時(shí)候,您就可以考慮用靜態(tài)工廠方法來(lái)實(shí)例化對(duì)象了。因?yàn)殪o態(tài)工廠方法有一個(gè)最簡(jiǎn)單的特點(diǎn)就是:他有可以變化的方法名(構(gòu)造器的名字變不了)。用名字的不同來(lái)代表不同的構(gòu)造需要,這么簡(jiǎn)單的普通的特點(diǎn)在這里就是它相對(duì)于構(gòu)造器的
advantage
。
如上面的錘子的例子可以這樣:
1
:
Hammer.produceByWeight (Color c, int kg){
//remainder omited
}
2
:
Hammer.produceByHeight (Color c, int cm){
//remainder omited
}
這是不是一目了然多了。嗯,我是這樣認(rèn)為的。
第二個(gè)好處,“靜態(tài)工廠方法不需要每次都真的去實(shí)例化一個(gè)對(duì)象”——其實(shí)這也是另一些優(yōu)化方法的前提。
構(gòu)造器的每次
invoke
必定會(huì)產(chǎn)生一個(gè)新的對(duì)象,而靜態(tài)工廠方法經(jīng)過(guò)一定的控制,完全可以不用每次
invoke
都生成一個(gè)新的對(duì)象。
為什么不每次都生成一個(gè)對(duì)象的原因就不必說(shuō)了,因?yàn)樵蛱黠@。這個(gè)原因就是為什么要“共享”對(duì)象的原因。
下面講講通常使用的兩種共享具體策略,也就是具體方法了:
1
:?jiǎn)卫J降男枰坏┬枰硞€(gè)對(duì)象有單例的需要,必定對(duì)于這類(lèi)對(duì)象的構(gòu)造只能用靜態(tài)工廠方法了。
2
:
flyweight
模式和不變(
immutable
)
模式的需要,這兩個(gè)模式很多時(shí)候都說(shuō)一起使用的,一旦一些對(duì)象我們認(rèn)為是不變的,那自然就想拿來(lái)重用,也就說(shuō)共享,而
flyweight
就是用來(lái)重用這些小粒度對(duì)象的。
如
Boolean.valueOf (boolean)
方法:
Boolean a = Boolean.valueOf (100);
Boolean b = Boolean.valueOf (100);
?a,??b兩個(gè)引用都是指向同一個(gè)對(duì)象。
這些對(duì)象都是不變的,而
valueOf
的控制就是用的
flyweight
方法。
這種一個(gè)狀態(tài)(如上面一個(gè)數(shù)字)對(duì)應(yīng)的對(duì)象只有一個(gè)還有一個(gè)好處,就是可以直接通過(guò)比較“引用”來(lái)判斷他們是否
equel
(這里的
equel
是邏輯相等的意思),以前需要
a.equels(b)
,而一旦用“
flyweight
模式和不變(
immutable
)
模式”后,避免了產(chǎn)生多余的相同對(duì)象,用
a==b
就可以達(dá)到
a.equels(b)
的目的了。這樣當(dāng)然優(yōu)化了
performance
。??
第三個(gè)好處,其實(shí)就是工廠方法的核心好處——我把它稱(chēng)為“抽象類(lèi)型構(gòu)造器”。它可以為我們提供一個(gè)抽象類(lèi)型的實(shí)例,同時(shí)必要的隱藏了抽象類(lèi)型的具體結(jié)構(gòu)。這是
new
怎么都達(dá)不到的。
這種模式的好處其實(shí)就是面向?qū)ο蟮淖詈诵牡暮锰帲橄蠛途唧w可以分離,一旦抽象定義好了,具體的東西可以慢慢的變化,慢慢的拓展——開(kāi)閉原則。
如
Collections Framework API
,都是描述集合類(lèi)型的接口,也就是對(duì)于客戶(hù)端來(lái)看,只有
Collection
這個(gè)類(lèi)要認(rèn)識(shí),而實(shí)際上,實(shí)現(xiàn)這個(gè)接口的
Collection
是多種多樣的。如果要讓用戶(hù)都知道這些具體實(shí)現(xiàn)的
Collection
,就增加了復(fù)雜度。
這時(shí),通過(guò)一個(gè)靜態(tài)工廠方法,就可以隱藏各種
Collection
的具體實(shí)現(xiàn),而讓
Client
只使用返回的
Collection
對(duì)象就可以了。
這里還可以加上一些權(quán)限控制,如這些實(shí)現(xiàn)只要對(duì)于工廠來(lái)講是可以訪問(wèn)的,不用是
public
的,而他們只要通過(guò)
public
的工廠就可以提供給用戶(hù)。非常有利于代碼的安全。
靜態(tài)工廠方法的第一個(gè)缺點(diǎn)就是:使用靜態(tài)工廠方法創(chuàng)建的類(lèi)的構(gòu)造器經(jīng)常都是非公共或非
protected
的。
這樣,以后這些類(lèi)就沒(méi)有辦法被繼承了。不過(guò)也有人說(shuō),不用繼承就用
composition
唄。也是!呵呵。
靜態(tài)工廠方法的第二個(gè)缺點(diǎn)是:在
jdk
文檔里,這些靜態(tài)工廠方法很難跟別的靜態(tài)方法相區(qū)別。
而文檔中,構(gòu)造器是很容易看到的。
為了一定程度解決這個(gè)問(wèn)題,我們可以用一些比較特別的名字來(lái)給這類(lèi)靜態(tài)工廠方法來(lái)命名。最常用的有:
valueOf
——
用來(lái)放回跟參數(shù)“相同值”的對(duì)象。
getInstance
——
返回一個(gè)對(duì)象的實(shí)例。單例模式中,就是返回單例對(duì)象。
總結(jié):靜態(tài)工廠方法和構(gòu)造器都有各自的特點(diǎn)。最好在考慮用構(gòu)造器之前能先考慮一下靜態(tài)工廠方法,往往,后者更有用一點(diǎn)。如果權(quán)衡了以后也看不出那個(gè)好用一些,那就用構(gòu)造器,畢竟簡(jiǎn)單本分多了。