锘??xml version="1.0" encoding="utf-8" standalone="yes"?> 鍏堣窇涓嬮鑱婅亰java. 榪戜袱騫磋秺鏉ヨ秺澶氭悶Java鐨勪漢璺戝幓瀛﹀姩鎬佽璦錛宺uby, groovy, scala涔嬬被鐨勩?鍘熷洜鍦ㄤ簬榪欎簺鍔ㄦ佽璦鈥滆〃杈捐兘鍔涒濇洿濂姐傛槸鐨勶紝榪欎簺璇█鏇寸伒媧伙紝鏇寸簿鐐箋備笉闅劇悊瑙o紝鍚庡嚭鐨勭紪紼嬭璦鏇村懼悜浜庡悎鐞嗭紝姣曠珶瀹冩湁鍓嶄漢鐨勫疂璐電粡楠屽彲浠ュ熼壌銆俲ava鐨勪竴浜涜璁$殑紜護(hù)浜鴻療鐥咃紝姣斿checked exception, 瀵規(guī)硾鍨嬫敮鎸佺殑涓嶅畬澶囥備絾灝變粠鈥滆〃杈懼姏鈥濇潵璇達(dá)紝鎴戣寰梛ava鐨勮〃杈懼姏涓嶅己涓嶅急姝f濂藉ソ銆侸ava鐨勫畾浣嶆湰鏉ュ氨鏄ぇ瑙勬ā浼佷笟綰у簲鐢紝榪囧害鐏墊椿鐨勭紪紼嬭璦涓嶆槗緇存姢銆?/strong>鏂板瀷鐨勫姩鎬佽璦鍊懼悜浜庤繃搴︾伒媧伙紝铏界劧鏀寔蹇熷紑鍙戯紝浣嗘槸鎴戠浉淇″湪澶氫漢錛岀敋鑷沖嚑鍗佷漢鍚堜綔寮鍙戠殑欏圭洰涓紝濡傛灉瀵硅璦闈炲父鐏墊椿鐨勭壒鎬т笉鍔犱互闄愬埗錛岄殢鐫紼嬪簭鐨勮妯′竴鐐圭偣澧炲ぇ錛岀淮鎶ょ殑闅懼害浼?xì)闄$劧鍔犲ぇ銆傝屼竴鏃﹂氳繃convention闄愬埗浣跨敤璇█鐨勪竴浜涚壒鎬э紝闄愬埗鏉ラ檺鍒跺幓涓嶅氨鍙堟垚java浜嗕箞錛熷ソ鍚э紝濂藉惂錛屾垜鐭ラ亾榪欎細(xì)鏄釜鏈変簤璁殑璇濋錛屾垜灝辨槸涓嶇浉淇$敤ruby鑳藉仛涓狤RP鍑烘潵錛屼簲騫翠箣鍚庝篃涓嶄細(xì)鏈夈傝繖涓嶆槸榪欑瘒鏂囧瓧瑕佽璁虹殑閲嶇偣錛屾垜鎯寵鐨勬槸錛宩ava鍦ㄨ〃杈捐兘鍔涙柟闈㈠凡緇忚涓浜涗漢涓嶆弧鎰忎簡錛岃孹ML鍛紵XML鐨勮〃杈捐兘鍔涙瘮java宸簡N澶氫釜鏁伴噺綰э紒榪欏勾澶達(dá)紝楠戜笁杞濺鍥炴敹鐢?shù)鑴戠殑閮界煡閬摻E嬪簭璁捐瑕佹湁寮規(guī)э紝鎹㈠彞璇濊錛岃兘閫傚簲鍙樺寲銆備簬鏄竴涓畝鍗曠殑姊︽兂灝辨槸錛屾潵浜嗘柊闇姹傦紝鍜變笉鐢ㄦ敼code, 鏀規(guī)敼xml閰嶇疆灝辮兘婊¤凍灝卞ソ浜嗐傛槸鐨勶紝鎴戜篃榪欎箞甯屾湜錛屽挨鍏跺湪鎴戠潯鐫鐨勬椂鍊欍備互Java榪欐牱鐨勯潰鍚戝璞?+ 涓浜涘姩鎬佺壒鎬э紙reflection錛宒ynamic proxy鐢氳嚦aspectJ錛夌殑璇█閮藉緢闅懼仛鍒板姝ょ伒媧葷殑搴斿鍙樺寲錛寈ml鎬庝箞浼?xì)鏇村?guī)槗鍋氬埌鍛紵寰堝浜哄枩嬈ML鐨勭畝鍗曠洿瑙傘傛瘮濡傛垜浠彲浠ュ湪SWING涓婇潰灝佽涓灞傚熀浜嶺ML鐨勭晫闈㈠紩鎿庯紝浜庢槸GUI灝卞彲浠ョ畝鍗曞湴鍐欐垚榪欑椋庢牸錛?/p> 瀹冩湁涓涓ソ澶勫氨鏄槗浜庢墿灞曪紝姣斿鐜板湪鍙堟兂鍔犱竴涓猚hecked box,鍙鍦ㄩ噷闈㈡彃鍏ヤ竴涓?lt;checkbox id=鈥︹?>灝辮浜嗐傛垜鎵胯瀹冪殑紜槗浜庢墿灞曘備絾鏄鏋滀綘綆鍗曞皝瑁呬竴涓媕ava API錛屼笉涔熸槸涓琛宑ode鐨勪簨鍎夸箞錛熸棤闈炲氨鏄痯anel.addChild(new CheckedBox(attr_1, attr_2))涔嬬被鐨勮繖涔堜竴鍙ode銆傞毦閬撹繖灝變笉綆鍗曪紝涓嶇洿瑙備簡錛熺▼搴忎竴娑夊強(qiáng)鍒皒ml,灝辨秹鍙?qiáng)鍒癐O, 瑙f瀽XML錛岃繖閮芥槸棰濆鐨勫伐浣滈噺錛屽喌涓攛ml涓殑鈥滃璞♀濓紙鎴戝緢闅炬壙璁omplex type綆楁槸瀵硅薄錛夎窡Java閲岀殑瀵硅薄鏍規(guī)湰涓嶆槸涓鐮佷簨錛屼粠xml閲岃В鏋愬嚭鏉ョ殑琛ㄧず鏁版嵁綾誨瀷鐨則ype鏈鍚庤繕鏄鐢熸垚瀵瑰簲鐗瑰畾鐨刯ava瀵硅薄錛岃繖閮芥槸楹葷儲(chǔ)浜嬪効銆?澶氬啓code鐨勫潖澶勮繙涓嶆鍐欑殑鏃跺欒垂浜嬪効錛屾墍鍐欑殑姣忚code鏈鍚庨兘鏄緇存姢鐨勶紝灝辯畻code寰坰trong, 鎴戣繕瀚宑ode澶暱錛屾粴榧犳爣婊氳疆鍎跨瘡鎵嬫寚澶達(dá)紝澶氫釜鏂囦歡鏀鵑偅鍎跨瘡鑺辯溂銆?strong>鎬諱箣錛屼絾鍑ml鏀逛竴涓よ鑳借В鍐崇殑闂錛屼笉鐢▁ml,灝辯敤java涔熸槸涓涓よ鐨勫伐浣滈噺錛屽彧瑕佺◢寰姳鐐瑰績鎬濆皝瑁呭ソAPI灝辮銆?/strong>涓嶇敤XML鍙互鐪佷笉灝戝紑鍙戝拰緇存姢鐨勫伐浣溿傜悊鎯蟲儏鍐典笅錛屾敼鏀箈ml灝辮兘搴斿鏂伴渶姹傘備絾鐜板疄鍜岀悊鎯蟲繪槸鏈夊樊璺濈殑錛屼竴鏃ml鐨剆chema涓嶈凍浠ュ簲瀵瑰彉鍖栵紝鎴戜滑灝卞緱鏀箈ml, 鏀箂chema錛屾敼瑙f瀽鐨刢ode錛屾敼涓氬姟閫昏緫鐨刢ode錛堣繖涓病娉曢伩鍏嶏級(jí)銆傝繖涓嶆槸娌′簨鍎挎壘鐥呬箞錛?strong>xml鏄痚xtendable markup language. 瀹冪湡鑳芥瘮java榪榚xtendable錛?/strong>鎵貳錛?/p>
褰撶劧XML鏈夊畠鍚堢悊鐨勫簲鐢ㄥ満鏅紝鎴戣兘鎯沖埌鐨勬槸鍥涗釜鏂歸潰錛屼竴瀹氭湁婕忔帀鐨勬儏鍐碉紝嬈㈣繋鏈嬪弸浠ˉ鍏呫?/p>
涓錛?瀛樺偍鏍?wèi)鐘舵暟鎹Q堣搗鐮佷笁灞備互涓娿備笁灞傛垨涓夊眰浠ヤ笅灝辯敤java鍚堟垚涔熸尯鏂逛究鐨勶級(jí)錛涗簩錛?閰嶇疆淇℃伅錛涗笁銆佹弿榪版爣鍑嗗崗璁紙姣斿wsdl錛夛紱 鍥涳紝wrap鏁版嵁浠ヤ究浜庝紶杈撶瓑(姣斿soap) 鍦ㄥ簲鐢ㄤ駭鍝佷腑錛岃嚜宸辮璁ml鏉ヨ緟鍔╁簲鐢ㄧ郴緇熺殑鍦烘櫙涓嶅簲璇ュ緢澶氥?/strong> 鍙︽湁涓縐嶄嬌鐢▁ml鐨勮鍖烘槸錛屾妸xml鏆撮湶緇欑敤鎴瘋浠栬嚜宸扁滄墿灞曗濄傛垜瑙夊緱錛?鍑℃槸鏆撮湶緇欏鎴風(fēng)殑涓滆タ閮芥槸UI錛屽鉤鏃禨wing鐣岄潰錛寃eb鐣岄潰鏄疓UI錛屾毚闇茬粰瀹㈡埛鏀圭殑xml綆楁槸UI. 涔熻鏈夌殑浜鴻錛屼竴鏃﹀紕GUI錛屽氨鏈変竴鍫嗛夯鐑?chǔ)浜嬪効锛屾瘮濡俰18n鍟ョ殑錛岃鐢ㄦ埛鑷繁閰嶇疆閰嶇疆xml灝辮兘鏀瑰姩欏甸潰涓嶆槸鎸哄ソ涔堬紝榪樹笉鐢ㄨ冭檻i18n浜嗐傞棶棰樻槸錛岀敤xml涓嶆槸鈥滀笉鐢ㄢ濊冭檻鍥介檯鍖栵紝鑰屾槸鏍規(guī)湰娌℃硶鑰冭檻鍥介檯鍖栥?/p>
<wallet><money>100</money></wallet> 榪欎釜緹庡浗浜鴻兘鐪嬫噦錛屽涓浗浜哄氨寰楃敤<閽卞寘><閽?gt;100</閽?gt;</閽卞寘> 榪欎箞鍋氬緢鏄庢樉鐢ㄦ埛浣撻獙寰堝樊銆傚彟澶栵紝榪欎篃涓瀹氱▼搴︿笂鏆撮湶浜嗕綘鐨勫疄鐜版柟寮忥紝璧風(fēng)爜瀹㈡埛鐭ラ亾錛屽摝錛屽師鏉ヤ綘鏄敤xml瀛樻暟鎹殑錛宻chema灝辨槸榪欎釜鏍峰瓙銆?/p>
Ajax鍒氶摵澶╃洊鍦扮殑鏃跺欙紝閮界敤xml浼犳暟鎹紝鍚庢潵瓚婃潵瓚婂浜虹敤Json. Spring鍜孒ibernate絳変竴鍫嗘鏋跺湪鍑犲勾鍓嶉兘鐢ㄥ法澶х殑XML鏉ラ厤緗紝鐜板湪瓚婃潵瓚婂浜鴻漿鍚慳nnotation(褰撶劧錛岃繖涓湁涓瀹氫簤璁?銆俋ML鐑害鍑忛錛屽ぇ瀹惰秼浜庣悊鎬ф槸濂戒簨銆俋ML褰撶劧寰堟湁鐢紝浣嗘槸紼嬪簭鍛樹滑璇ヨ兘鎯蟲竻妤氫粈涔堟槸"浣跨敤", 浠涔堟槸"婊ョ敤". Domain Driven Design鍩轟簬涓浜涚畝鍗曪紝閲嶈錛屽姟瀹炵殑鐞嗗康銆備笅闈㈡牴鎹嚜宸辯殑鐞嗚В鎬葷粨DDD鐨勫熀鏈悊璁恒?/p> 1. 娣卞埢鐞嗚ВDomain鐭ヨ瘑 DDD寮鴻皟鍩轟簬domain榪涜璁捐銆傚墠鎻愭槸娣卞埢鐞嗚В棰嗗煙鐭ヨ瘑錛岄渶瑕佹寔緇涔?fàn)銆傚彟涓涓浉鍏崇殑瀹炶返鏄紝鈥滅粺涓鐨勮璦鈥濓紙ubiquitous language錛夈傞鍩熶笓瀹舵墍鐢ㄧ殑鏈鏄噯紜殑錛岄偅涔堢▼搴忓憳璁ㄨdomain鐩稿叧鐨勯棶棰樻椂錛屼篃搴旇浣跨敤榪欑鏈銆傚茍涓斿湪鍐檆ode鐨勬椂鍊欙紝涔熶嬌鐢ㄨ繖縐嶆湳璇傝繖鏍峰仛鐨勫ソ澶勬槸錛屽彲浠ヨ嚜鐒跺湴鎶奷omain鐨勪笢瑗縨ap鍒癱ode閲岋紝淇濇寔code鍙嶅簲domain銆?/p> 2. 鍒嗗眰 紼嬪簭闇瑕佸垎灞傦紝榪欐槸涓畝鍗曠殑閬撶悊, 浣嗛渶瑕佺湡姝e艦鎴愭剰璇嗐?/p> 鍒嗗埆璇磋Domain Driven Design娑夊強(qiáng)鐨勫洓涓猯ayer. 2.1 Infrastructure灞?/p> 涓昏浠庢妧鏈笂瀵逛笂闈㈢殑鍚勫眰鎻愪緵鏀寔銆傛瘮濡備紶閫佹秷鎭紝鎸佷箙鍖栥俇I灞備篃鍙互鍒嗗嚭鏇村熀紜鐨刢omponent浣滀負(fù)infrastructure灞?/p> 2.2 UI灞?/p> UI灞傜殑浣滅敤鏄樉紺轟俊鎭互鍙?qiáng)瑙i噴鐢ㄦ堬L(fēng)殑杈撳叆鍛戒護(hù)銆傞噸瑕佺殑鏄疷I灞傛病鏈塪omain knowledge. 2.3 application灞?/p> application灞傜殑浣滅敤鏄弿榪頒駭鍝佺殑澶栭儴鍔熻兘錛屽畠鍙互鍗忚皟UI鍜孌omain灞傜殑浜掑姩銆?strong>application灞傚簲璇ュ緢钖?/strong>銆傚畠娌℃湁domain knowledge. 2.4 Domain灞?/p> Domain灞傛槸鏈閲嶈鐨勫眰銆傚皝瑁呮墍鏈夌殑涓氬姟閫昏緫銆?/p> DDD涔熶粠鍙︿竴涓搴﹀垎瑙h蔣浠躲備竴涓蔣浠剁殑緇勬垚閮ㄥ垎錛坆uilding block錛夊寘鎷琣ssociation, entity, value object, service, module銆傚叾涓瘮杈冨己璋冪殑鏄痚ntity, value object鍜宻ervice. service姣旇緝瀹規(guī)槗鐞嗚В錛岄氬父瀹冩槸鏃犵姸鎬佺殑銆傚畠鍙互瀛樺湪浜巃pplication灞傦紝domain灞傛垨鑰卛nfrastructure灞傘傛瘮杈冧笉瀹規(guī)槗鍖哄垎鐨勬槸entity鍜寁alue object. entity寮鴻皟鐨勬槸瀹冪殑id錛岃屼笉鏄睘鎬с傚己璋冨畠鐢熷懡鍛ㄦ湡鐨勭戶緇у拰鍚屼竴鎬?continuity and identity), 鑰?strong>value object鏄敤鏉モ滄弿榪扳漞ntity鐨?/strong>銆倂alue object鍦ㄥ緢澶氭椂鍊欓傚悎鏄痠mmutable鐨勩傝繖閲岄渶瑕佹敞鎰忕殑鏄紝濡傛灉浣犱細(xì)浣跨敤hibernate,浣犱細(xì)鐭ラ亾hibernate閲岀殑value object閫氬父涓嶈兘reference澶氫釜entity錛屾崲鍙ヨ瘽璇達(dá)紝鑳絩eference澶氫釜entity鐨勶紝閫氬父灝辨槸entity. 鑰屽湪DDD鐨勭悊璁轟腑錛?璺嚎"鏄竴涓獀alue object銆傝屽畠鍙互reference榪炴帴"璺嚎"鐨刢ity(entity)鍜岄珮閫熷叕璺?entity)銆?/p> 3. Domain Object鐢熷懡鍛ㄦ湡 DDD鐨勪竴涓噸瑕佺悊璁烘槸鍏充簬aggregate. domain object涔嬮棿鐨勫叧緋誨鏋滈潪甯稿鏉傦紝鍦╠omain knowledge娑夊強(qiáng)姣旇緝澶嶆潅鐨剅ule鐨勬椂鍊欙紝瀹規(guī)槗閫犳垚涓嶄竴鑷寸殑鎯呭喌銆傝В鍐沖姙娉曟槸錛屾妸涓浜沝omain object鏀句竴涓粍閲岋紝璁╂煇涓猟omain object浣滀負(fù)鏍癸紙aggregate root錛? 鎵鏈夊榪欎簺domain object鐨勮闂兘瑕侀氳繃榪欎釜aggregate, 閭d箞緇存寔涓鑷存х殑宸ヤ綔錛屽氨闄愬埗鍦ㄨ繖涓猘ggregate root閲屼簡銆?/p> 鍙︿竴涓浉鍏崇悊璁烘槸factory鍜宺epository. factory鏄敤鏉モ滃垱寤衡濆璞$殑錛屾槸涓涓粠鏃犲埌鏈夌殑榪囩▼銆傝宺epository鏄敤鏉etrieve瀵硅薄鐨勶紝涔熷氨鏄錛屽璞″瑙傚瓨鍦紝鍙槸娌℃湁鏀懼湪鍐呭瓨涓紝repository灝辨槸鎶婃暟鎹粠鏌愪釜鍦版柟錛堥氬父鏄暟鎹簱錛夋嬁鍑烘潵錛宑onstruct鎴愬璞$殑銆備竴涓父瑙佺殑璁捐鏄紝璁﹔epository鏆撮湶retrieve鍜宑reate鐨刟pi錛屼絾鏄痗reate鐨勫叿浣撳伐浣滀唬鐞嗙粰factory鏉ュ仛錛屼篃灝辨槸璇達(dá)紝factory閫氬父琚仛鍚堝湪repository涓?/p> 1: <panel id=鈥?span style="color: #ff0000">xyz鈥?width=鈥?span style="color: #ff0000">360鈥?heigh=鈥?span style="color: #ff0000">720鈥濃︹?span style="color: #0000ff">>
2:
3: <label id=鈥?span style="color: #ff0000">label_1鈥?attr_1=鈥?span style="color: #ff0000">xxx鈥?attr_2=鈥?span style="color: #ff0000">yyy鈥?span style="color: #0000ff">/>
4:
5: <textarea id=鈥?span style="color: #ff0000">textarea_1鈥?attr_1=鈥?span style="color: #ff0000">xxx鈥?attr_2=鈥?span style="color: #ff0000">yyy鈥?span style="color: #0000ff">/>
6:
7: </panel>
]]>Layered Architecture
]]>
Eric Evans has formulated what domain-driven design (DDD) is. Martin Fowler is a great supporter and advocate of DDD. These are remarkable names and it is almost certain they are supporting something worth. And I鈥檓 not here to argue with that. Maybe I鈥檓 trying to justify the way I鈥檝e been writing software, or maybe I鈥檓 trying just to clear things and be constructive. Let鈥檚 see.
What is at the core of domain-driven design 鈥?the abstract notions of the domain, the domain model, the ubiquitous language. I鈥檒l not go into details with that 鈥?for those interested there is wikipedia (with lots of references to read in the footer). This is all very good in theory, and the domain-driven way of building software should appeal to everyone 鈥?after all that software is being built for the benefit of that domain, not for the benefit of architects, developers or QAs.
But now comes the practical part 鈥?how to implement DDD? I鈥檒l answer that question in its contemporary context 鈥?that is, using frameworks like spring and hibernate. And I鈥檒l justify their usage. Spring is a non-invasive dependency-injection framework. DI is also strongly supported by Fowler, and is considered a good way to implement DDD. Hibernate is one way to use objects when working with a relational database. Another way is to use JDBC and construct the objects manually, but that is tedious. So hibernate doesn鈥檛 influence the architecture part 鈥?it is an utility (very powerful one, of course).
Throughout this post I鈥檒l use hibernate and spring as 鈥済iven鈥? although they may be changed with any DI framework and any ORM or other persistence mechanism that relies on objects.
The accepted way to implement DDD with spring and hibernate is:
@Configurable
to make the domain objects eligible for dependency injection (they are not instantiated by spring, so they need this special approach) Implementation and description of this approach is shown in this extensive article. Another example (without spring) is http://dddsample.sourceforge.net/. I鈥檒l discuss both later.
The alternative to this approach is the anemic domain model. It is considered an anti-pattern, but at the same time is very common and often used. The features of the anemic data model are simple 鈥?the domain objects have no business logic inside them 鈥?they are only data holders. Instead, the business logic is placed in services.
The reason this is considered an anti-pattern is because, first, this seems like a procedural approach. It is breaking the encapsulation, because the internal state of the object is, well, not internal at all. Second, as the domain object is the center of the design, it is harder to change it if its operations don鈥檛 belong to it, but to a number of stateless service classes instead. And domain-driven design is aimed at medium-to-large scale applications, which change a lot and need an easy way to make changes fast, without breaking other functionality. Thus it is important to have all the functionality of the object within the object itself. This also makes sure that there is less duplication of code.
So, instead of having a service calculate the price: ProductServiceImpl.calculatePrice(complexProduct)
we should simply have ComplexProduct.calculatePrice()
. And so whenever the domain experts say that the price calculation mechanism changes, the place to change it is exactly one and is the most straightforward one.
When simple operations are regarded, this looks easy. However, when one domain objects needs another domain object to do its job, it becomes more complicated. With the anemic data model this is achieved by simply injecting another Service into the current one and calling its methods. With the proposed DDD it is achieved by passing domain objects as arguments.
In my view, the domain object, which is also the hibernate entity, has its dependencies already set. But not by spring, because spring can鈥檛 know which exactly domain object to inject. They are 鈥渋njected鈥?by hibernate, because it knows exactly which (identified by primary key) domain object should be placed in another domain object. So, a little odd example 鈥?if a Product
has rotten and has to dispense smell in the warehouse, it has to call, for example, warehouse.increaseSmellLevel(getSmellCoeficient())
. And it has its precise Warehouse
without any interference from spring.
Now, here comes another point where I disagree. Most sources (including the two linked above) state that repositories / DAOs should be injected in the domain objects. No, they shouldn鈥檛. Simply calling 鈥渟ave鈥?or 鈥渦pdate鈥?doesn鈥檛 require knowledge of the internal state of the object. Hibernate knows everything anyway. So we are just passing the whole object to the repository.
Let鈥檚 split this in two 鈥?business logic and infrastructure logic. The domain object should not know anything of the infrastructure. That might mean that it should not know it is being saved somewhere. Does a product care of how it is stored ? No 鈥?it鈥檚 the storage mechanism that鈥檚 鈥渋nterested鈥? And here are the practical disadvantages:
I鈥檒l open a bracket here about a proposed solution in one of the above articles for making duplication of code, and boilerplate code easier to handle. Code generation is suggested. And I think code-generation is a sin. It moves the inability to get rid of duplicated or very similar code and abstract it, to tools. The most striking example is generating ProductDAO, CategoryDAO, WarehouseDAO, etc, etc. Generated code is hard to manage, cannot be extended and relies heavily on external metadata, which is definitely not an object-oriented approach.
Speaking of the repository, in the proposed examples each domain object should have a repository, which in turn will call the persistence mechanism. What do we get then:
User presses 鈥渟ave鈥?in the UI > UI calls save on the service (in order to have transaction support) > Service calls save on the domain object > domain object calls save on the repository > the repository calls save on the persistence mechanism > the persistence mechanism saves the object.
Is it just me, or calling the domain object is redundant here. It is a pass-through method that adds nothing. And since a lot of functionality is related to CRUD (yes, even in big business applications), this looks quite bad to me.
And finally, I find the @Configurable
approach a hack. It does some magic in the background, which isn鈥檛 anything of the common language features (and is not a design pattern), and in order to understand how it happens you need a great deal of experience.
So, to summarize the big mess above
=================================================
涓涓湁瑙佸湴鐨勫洖澶嶏細(xì)
For one I think that technical issues should be separated from the functional domain. That means that domain objects should not be polluted by (technical) annotations or persistence methods (seperation of concerns). Dependency Injection (technical) should be outside the core domain. Persistence methods should be in a repository gateway, which (at least the interface, functional) is part of the domain. You know that you have a repository (functiuonal, within the domain), but not the way it鈥檚 implemented (technical). That鈥檚 outside the domain.
Just as the services (functionality) which calls them are part of the domain. These services are called from the user interface or other components outside this particular domain.
Transactional boundaries and session management is not domain functionality and should be outside the domain in a separate (thin) layer, which calls the services or domain objects within the domain.
DTO鈥檚 are useful for communicating outside the domain. In simple applications (with session management in the UI) the DO鈥檚 can be used, but I would not recommend it. I prefer the use of DTO鈥檚 which are assembled within the transaction boundary, and can be used outside the transaction (and session) boundary as to avoid potential LazyInitializationExceptions, which I am, unfortunately, very familiar with.
Dependency injection should not be in Domain Objects. If you want to use something like the AgeCalculator mentioned above, just call the user.getAge() method wich Alex suggested.
This method contains something like
class User {
public int getAge() {
AgeFactory.getInstance().getAgeCalculator().calculateAge(this);
}
}
The AgeFactory is a singleton, which has the correct calculator injected. You can use Spring for that.
class AgeFactory {
AgeFactory instance = new AgeFactory();
AgeCalculator ageCalculator = null;
public AgeFactory getInstance() {
return instance;
}
public void setAgeCalculator(AgeCalculator ageCalculator) {
this.ageCalculator = ageCalculator;
}
public AgeCalculator getAgeCalculator() {
return this.ageCalculator;
}
}
The implementation of the repository gateway objects can be done in the same way.
Usage of the repository (in a service) can be something like this
class ServiceImpl implements Service {
public void save(User user) {
RepositoryFactory.getInstance().getUserRepository().save(user);
}
}
These factories must be within the domain, because the domein objects must use them. But the dependency injection of these factories can be done outside the core domain (if you don鈥檛 use annotations). This way the core functional domain is not polluted with the technical issues of dependency injection.
Finally about annotations, I hate them, because it鈥檚 a magic black box. I rather use xml configuration files because they are probably easier to understand. Furthermore without annotations you can have the configuration files outside the core domain, and can use mock objects which are created and set on the factory without dependency injection within testcases. You can even choose to use dependency injection within part of the unit tests and without DI in other unit tests.