一個項目卓箫,由兩個人組成,小王和小明垄潮。小王為小明提供函數(shù)丽柿,將數(shù)據(jù)保存到數(shù)據(jù)庫當(dāng)中,小明不關(guān)心入庫細(xì)節(jié)魂挂。下面小明是調(diào)用小王的代碼甫题。
<pre><code>
InsertHouse(house);
InsertFridge(fridge);
InsertTelevision(television);
</pre></code>
每次小明調(diào)用三個函數(shù),創(chuàng)建一個房子涂召,以及為這個房子添加一個冰箱和電視機(jī)坠非。隨著開發(fā)不斷繼續(xù),小明發(fā)現(xiàn)一個很重要的問題果正,就是小王的函數(shù)接口并沒有支持事務(wù)炎码。在連續(xù)調(diào)用三個函數(shù)的中間,如果其中某次調(diào)用異常了秋泳,沒有合適的方式做到回滾潦闲。如果由小明在調(diào)用測采用try catch來處理,代碼會非常的丑陋迫皱。
<pre><code>
try{InsertHouse(house);}catch{DeleteHouse(house);}
try{InsertFridge(fridge);}catch{DeleteHouse(house);DeleteFridge(fridge);}
try{InsertTelevision(television);}catch{DeleteHouse(house);DeleteFridge(fridge);DeleteTelevision(television);}
</pre></code>
如果在刪除的時候再次出異常那該怎么辦歉闰?這么寫下去就無窮盡了。
在函數(shù)的基礎(chǔ)上支持事務(wù)的方法很多卓起,本文既不可能窮舉所有方案和敬,也沒有能力對所有方案一較高低,給出最優(yōu)方案戏阅,本文只能給出一個有點意思的方案昼弟。
小王和小明坐了下來,他們首先想到的是將函數(shù)壓縮成一個奕筐,在函數(shù)內(nèi)測支持事務(wù)舱痘,保證這次調(diào)用要么成功,要么就完全失敗离赫,不會產(chǎn)生垃圾數(shù)據(jù)芭逝。
InsertAllThings(house,fridge,television);
但是這樣一來,如果將來需要新增插入沙發(fā)該怎么辦笆怠?這就需要修改函數(shù)的參數(shù)個數(shù)铝耻,而且不斷新增下去誊爹,會越來越長蹬刷,而且有的時候瓢捉,并不是所有內(nèi)容需要同時插入,一個家里面办成,可能先只有電視機(jī)泡态,后來才買了冰箱和沙發(fā)。小王和小明又想到了另外一個方案迂卢,就是定義一個結(jié)構(gòu)某弦,來表達(dá)要插入的數(shù)據(jù)。
obj.house=house;
obj.fridge=fridge;
obj.television=television;
InsertAllThings(obj);
這樣函數(shù)參數(shù)固定下來了而克,但是隨著支持新增沙發(fā)靶壮,那么obj的參數(shù)要不斷新增。
還有沒有更好的方法呢员萍?采用' 柯里化'的風(fēng)格來支持腾降,保證單個函數(shù)的簡單整潔,又具備擴(kuò)展性碎绎。
Begin().InsertHouse(house).InsertFridge(fridge).InsertTelevision(television).Commit();
在函數(shù)Begin中返回一個內(nèi)部對象obj螃壤,后面每次調(diào)用Insert只是將參數(shù)保存在obj中,并且再次將obj返回筋帖,最后的Commit才是真正執(zhí)行插入數(shù)據(jù)庫操作奸晴。為了方便理解我給出部分函數(shù)的實現(xiàn)。
def Begin()
{return obj;}
def obj.InsertHouse()
{obj.house=house;return obj;}
def obj.Commit()
{//根據(jù)obj的參數(shù)來生成SQL語句日麸,然后入庫}
采用這種方式寄啼,使用者小明不用顯式關(guān)心obj的屬性,實現(xiàn)者小王可以不斷增加函數(shù)來新增支持其他家具或者電器代箭,并且每個新增的函數(shù)參數(shù)簡單辕录,都支持強類型檢查,容易理解梢卸。