[心得]编写服务端的相关设计心得及体会
最近接手公司服務(wù)端接口的相關(guān)編寫工作,遇到了一些問題,提出了一些想法,討論了一些問題,與項(xiàng)目經(jīng)理在方案選擇上有了一番爭吵(當(dāng)然,這種爭吵是家常便飯的事兒)。特此有了一些心得體會(huì)。
?
方法入?yún)⒌脑O(shè)計(jì)
?
我們在設(shè)計(jì)程序的時(shí)候,如果使用常規(guī)的分層模型,既Controller、Service、Dao,來對(duì)項(xiàng)目進(jìn)行分層,一定會(huì)遇到一個(gè)問題,就是不同層及之間,數(shù)據(jù)傳遞,即每個(gè)方法的“入?yún)ⅰ睉?yīng)該怎么設(shè)計(jì)。
我曾待在一家從事銀行系統(tǒng)開發(fā)的公司,項(xiàng)目有一個(gè)很大的特點(diǎn),它并非使用C、S、D來進(jìn)行分層開發(fā),當(dāng)然這不是重點(diǎn),重點(diǎn)是它雖然使用Java,但是大部分不以面向?qū)ο蟮男问絹砭帉懗绦?#xff0c;項(xiàng)目中隨處可見的是static的靜態(tài)方法,幾乎什么功能都可以用靜態(tài)方法來完成,我的理解它已然是一個(gè)用java以面向過程的思想開發(fā)的項(xiàng)目。這個(gè)項(xiàng)目在方法之間傳遞數(shù)據(jù)時(shí),不適用對(duì)象封裝,而是采取多個(gè)入?yún)⒌男问?#xff0c;所以很常見的就是要一個(gè)方法,有N多個(gè)入?yún)?#xff0c;5個(gè)是常見、10個(gè)都不特殊。這種方式來編寫方法,有一定的缺點(diǎn):
- 在閱讀代碼的時(shí)候,經(jīng)常會(huì)不明白參數(shù)的意義,而需要仔細(xì)的去看javaDoc上的注釋,影響效率;
- 調(diào)用一些工具時(shí),因?yàn)椴皇且悦嫦驅(qū)ο蟮姆绞饺ピO(shè)計(jì)程序,所以所有變量的作用域自然只在方法體內(nèi),于是對(duì)于一些需要設(shè)置參數(shù)的工具,簡單的例如:分頁工具,就需要通過一大堆的入?yún)?#xff0c;經(jīng)常會(huì)搞不懂入?yún)⒌囊饬x,每次調(diào)用起來需要重新設(shè)置一大堆的參數(shù)值;或者使用一個(gè)Map來裝載這些參數(shù),這樣帶來的問題就是你甚至不知道有什么參數(shù)需要設(shè)置,經(jīng)常會(huì)出現(xiàn)錯(cuò)誤。
當(dāng)然,會(huì)用這種方式來設(shè)計(jì)程序,當(dāng)初項(xiàng)目經(jīng)理的意思是說:由于變量的作用域僅僅存在于方法體內(nèi),當(dāng)方法執(zhí)行結(jié)束以后,變量就會(huì)進(jìn)入銷毀,能快速的回收內(nèi)存。雖然我并沒有真正的去測試過這個(gè)觀點(diǎn)的正確性,但就我對(duì)JVM的GC機(jī)制來說,這種做法,是不是會(huì)造成大量的垃圾對(duì)象,這樣GC就會(huì)頻繁被調(diào)用來回收這些對(duì)象,這反而是增加了內(nèi)存的消耗。
有了這次經(jīng)驗(yàn),我自然是非常反對(duì)為方法設(shè)置大量參數(shù)作為入?yún)?#xff0c;以對(duì)象作為數(shù)據(jù)載體,進(jìn)行傳遞,我認(rèn)為才是最好的方式。但,依然產(chǎn)生了一些問題。
?
要用什么對(duì)象來傳遞參數(shù)?
由于種種原因(這里就不需要深究為什么了),我們項(xiàng)目在設(shè)計(jì)接口的時(shí)候出現(xiàn)了一個(gè)討論的命題:
要用什么來接收來自前端的請求數(shù)據(jù)?又如何把前端想要的數(shù)據(jù),按照前端需要的數(shù)據(jù)接口形式,傳遞出去?
簡單介紹一下會(huì)有這個(gè)問題的背景:
我們在設(shè)計(jì)接口的時(shí)候,往往會(huì)遇到這種問題:一個(gè)數(shù)據(jù)接口所請求的數(shù)據(jù),分別來自于不同的數(shù)據(jù)庫表,而同時(shí)它們也可能在程序中,是分別屬于兩個(gè)不同的對(duì)象的成員屬性,那這個(gè)時(shí)候,我們要怎么去設(shè)計(jì)接口,如何返回?cái)?shù)據(jù)?
我先來揭曉一下這個(gè)討論結(jié)果的最終的決定:
我們項(xiàng)目因?yàn)椴幌M煌瑢釉趥鬟f數(shù)據(jù)是,不知道具體要傳遞的數(shù)據(jù)內(nèi)容,所以不希望我們使用Map來作為載體,而盡可能的使用對(duì)象來做。這一點(diǎn)我是沒有異議,表示很贊同,因?yàn)槲以蜕钍芷浜?#xff0c;Map真心不認(rèn)為是一個(gè)適合用于傳參數(shù)的載體,當(dāng)然這也不是一棍子打死,只是最好不要使用。但經(jīng)理讓我們這么做,新建一個(gè)特殊的對(duì)象,這個(gè)對(duì)象沒有任何實(shí)體意義,僅僅是為了接口的形式,而去設(shè)計(jì)的Class,然后把從數(shù)據(jù)庫中查詢出來的已經(jīng)映射成實(shí)體對(duì)象的數(shù)據(jù),拆包,根據(jù)對(duì)應(yīng)的成員對(duì)象再組裝到這個(gè)新的對(duì)象當(dāng)中。這句話可能不好理解,我舉一個(gè)例子:
有一個(gè)實(shí)體對(duì)象(我們叫他Class A),它有10個(gè)成員屬性,分別是:a、b、c、d.....;但是某個(gè)接口僅僅只需要請求這10個(gè)成員屬性中的某3個(gè)屬性,于是我就要為了這個(gè)接口,專門創(chuàng)建一個(gè)類(我們叫他:Class B),這個(gè)類只有3個(gè)成員屬性,沒有錯(cuò),Class B 只不過 是Class A的一個(gè)子集。
我們使用的是Mybatis框架,本身查詢出來的數(shù)據(jù),就已經(jīng)是一個(gè)實(shí)體類,具有最全的屬性,然后我要把這個(gè)實(shí)體類的每個(gè)接口請求的對(duì)應(yīng)屬性都get出來,然后再set到這個(gè)新類當(dāng)中。我把這個(gè)get的過程,稱作“拆包”,set的過程,稱作“裝包”。
當(dāng)然我不認(rèn)為這是一個(gè)好的設(shè)計(jì)思路。
?
使用實(shí)體類作為數(shù)據(jù)載體
?
我們之所以會(huì)選擇這種方式,也是有原因的,我們是以json形式返回?cái)?shù)據(jù),spirngMVC可以添加一個(gè)過濾器,把null值的屬性都去掉,所以我提出的觀點(diǎn)自然是通過實(shí)體對(duì)象來作為數(shù)據(jù)承載,一次簡單請求由一個(gè)實(shí)體對(duì)象來承載所有的請求數(shù)據(jù),并且承載數(shù)據(jù)庫返回的查詢數(shù)據(jù),這樣一次簡單請求自然就不會(huì)產(chǎn)生什么多余的對(duì)象和不必要的操作,然后通過json的not_null過濾器,把null的屬性過濾掉,這樣接口就干凈簡潔。
而且我們基本上都是以面向?qū)ο蟮姆绞絹碓O(shè)計(jì)程序的,關(guān)系型數(shù)據(jù)庫也基本上是根據(jù)實(shí)體來設(shè)計(jì)表結(jié)構(gòu),所以表和實(shí)體的映射非常容易設(shè)計(jì),關(guān)聯(lián)性很強(qiáng),每次數(shù)據(jù)傳遞接口也不會(huì)很多參數(shù),因?yàn)楫吘挂淮握埱笏枰臄?shù)據(jù),跟他發(fā)來的請求條件,都會(huì)有一定的關(guān)系,所以依據(jù)對(duì)象之間的嵌套關(guān)系,實(shí)體對(duì)象很容易作為數(shù)據(jù)載體進(jìn)行方法之間的傳遞。
但是,這樣不代表就完全沒有問題了,而這個(gè)問題我也不知道如何解決:
一個(gè)對(duì)象假設(shè)有10個(gè)成員屬性,而一次請求,有1個(gè)以上,但可能也就是2個(gè)或3個(gè)數(shù)據(jù)參數(shù)作為查詢條件,那我卻要為了這2-3個(gè)參數(shù),去實(shí)例化一個(gè)具有10個(gè)成員屬性的對(duì)象,雖然另外的7-8個(gè)成員屬性可能沒有值,但是不代表他們不消耗內(nèi)存。
這個(gè)問題我一直都想不通,是否有可以解決這類問題的辦法?項(xiàng)目重構(gòu),將經(jīng)常調(diào)用的參數(shù)進(jìn)行抽象成父類確實(shí)能夠緩解一點(diǎn),但也不能完全避免這種內(nèi)存的浪費(fèi)。
就算沒有值,也要設(shè)置一個(gè)默認(rèn)值來表示
?
但前端那邊提出了這樣一個(gè)問題,有的請求,某些字段確實(shí)會(huì)有出現(xiàn)沒有值的情況,即null的情況,那就會(huì)被過濾掉,結(jié)果鍵值都沒有,那我就不知道到底是后端沒有數(shù)據(jù),還是程序出錯(cuò)。于是提出,就算是null,也不能把鍵值去掉。
其實(shí)當(dāng)時(shí)我被這個(gè)問題問蒙了,也沒有什么好的解決辦法。但是回頭想一想。。。如果后端返回null,你前端就一定能夠確定,不是程序問題么?如果程序出問題,一樣會(huì)出現(xiàn)null的返回結(jié)果,數(shù)據(jù)設(shè)置失敗了還不也一樣會(huì)值為null。要分清楚這個(gè)問題,就要能夠確定這個(gè)值是否是“人造”的數(shù)據(jù)。
所以我認(rèn)為,不管是何種數(shù)據(jù)類型,都應(yīng)該盡量(同樣不能一棍子打死,有的數(shù)據(jù)確實(shí)沒辦法設(shè)置這種默認(rèn)值)去設(shè)置一個(gè)默認(rèn)值來作為這個(gè)數(shù)據(jù)沒有值的一個(gè)表示,如時(shí)間可以設(shè)置為00:00:00,正整數(shù)可以設(shè)置為-1。還有一些字段必填的自然要做好必填項(xiàng)的校驗(yàn)。
轉(zhuǎn)載于:https://www.cnblogs.com/wuxinzhe/p/6367927.html
總結(jié)
以上是生活随笔為你收集整理的[心得]编写服务端的相关设计心得及体会的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ajax方式表单拦截
- 下一篇: 【转】ASP.NET MVC框架下使用M