日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
貧血領(lǐng)域模型是如何導(dǎo)致糟糕的軟件產(chǎn)生

使用貧血領(lǐng)域模型通常被認(rèn)為是一種反模式,因?yàn)樗膭?lì)程序員無意義地重復(fù)編寫代碼。下面我將簡短(而瑣碎)地用一個(gè)例子來闡述這個(gè)是如何產(chǎn)生的。我們可以通過細(xì)致的規(guī)劃以及嚴(yán)格的編碼規(guī)范來避免其發(fā)生,但是同樣可以獲得較好的封裝。防止陷入貧血領(lǐng)域模型深坑的難度隨項(xiàng)目人數(shù)呈指數(shù)級增長。

創(chuàng)新互聯(lián)公司堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都做網(wǎng)站、網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的寧縣網(wǎng)站設(shè)計(jì)、移動媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

我相信所有人對面向?qū)ο蠖加兴J(rèn)識,但我卻有趣地發(fā)現(xiàn)一些看似毫無意義的小舉措?yún)s導(dǎo)致了最終一場大災(zāi)難。

 第一步:編寫貧血實(shí)體

在軟件開發(fā)的某些情況下,我們會在一個(gè)領(lǐng)域?qū)嶓w之外實(shí)現(xiàn)一些邏輯。這可能是由于一個(gè)明確的設(shè)計(jì)決定或者,更有可能,持久類不能引用外部服務(wù)造成了不能將這段邏輯實(shí)現(xiàn)在領(lǐng)域?qū)ο蟮膬?nèi)部。把外部服務(wù)(依賴)添加到實(shí)體對象中將會造成與數(shù)據(jù)庫的交互變的復(fù)雜而晦澀難懂。

 
 
 
  1. public class User {  
  2.    private final String name;  
  3.    private final String emailAddress;  
  4.  
  5.    public User(final String name, final String emailAddress) {  
  6.       this.name=name;  
  7.       this.emailAddress=emailAddress;  
  8.    }  
  9.  
  10.    public String getName() {  
  11.       return this.name;  
  12.    }  
  13.  
  14.    public String getEmailAddress() {  
  15.       return this.emailAddress;  
  16.    }  

 第二部:邏輯被實(shí)現(xiàn)在外部類中

一個(gè)開發(fā)組的成員決定他們需要一個(gè)用來操作這個(gè)實(shí)體的方法。這個(gè)方法(在我們的例子中)要調(diào)用到User對象,但它還需要用到一個(gè)User類所不知道的外部服務(wù)。這段邏輯被實(shí)現(xiàn)在一個(gè)幫助類(helper)或者說一個(gè)服務(wù)類(service)的方法中,并且以某種方式協(xié)助了這個(gè)實(shí)體。這個(gè)幫助類不包含自帶的數(shù)據(jù),并且僅僅從這個(gè)實(shí)體中獲取數(shù)據(jù)、修改其狀態(tài)。

 
 
 
  1. public class UserReminderService { // 用戶提醒服務(wù)  
  2.    private IMailService mailService; // 郵件服務(wù)  
  3.    private IMessageGeneratorService messageGeneratorService; // 消息生成服務(wù)  
  4.  
  5.    public void sendReminderMessage(final IUser user) { // 發(fā)送一個(gè)提醒  
  6.       String reminderMessage = this.messageGeneratorService.generateReminderMessage(user.getName);  
  7.       this.mailService.sendMessage(user.getEmailAddress(), reminderMessage);  
  8.    }  
  9.  
  10.    ...  

這個(gè)并不能實(shí)現(xiàn)在User實(shí)體中,因?yàn)槲覀兏緹o法在實(shí)體中取得郵件服務(wù)或者是消息生成器。到目前為止,這個(gè)看起來還不算很糟糕(我們很好地封裝了消息的創(chuàng)建以及郵件發(fā)送過程),但是這僅僅是“敗壞”的開始,然后馬上開始讓這些不警惕的開發(fā)者陷入災(zāi)難。

哪里錯(cuò)了呢?

UserReminderService是一個(gè)游手好閑的類(它掌管了太多其他類的活動)。消息的創(chuàng)建、把它發(fā)送出去這些都應(yīng)該是User類自己的業(yè)務(wù)邏輯。

 第三步:重復(fù)代碼產(chǎn)生

在此期間,另一個(gè)開發(fā)者開發(fā)了一個(gè)全新的組件,同樣也使用了User實(shí)體。這個(gè)新的服務(wù)被用來決定注冊用戶是真的用戶而不是一個(gè)機(jī)器人。

 
 
 
  1. public class SignupVerificationService { // 注冊確認(rèn)服務(wù)  
  2.     private IMailService mailService; // 郵件服務(wù)  
  3.     private IMessageGeneratorService messageGeneratorService; // 消息生成服務(wù)  
  4.  
  5.     public void sendVerificationEmail(final IUser user) { // 發(fā)送確認(rèn)郵件  
  6.       String verificationMessage = this.messageGeneratorService.generateVerificationMessage(user.getName);  
  7.       this.mailService.sendMessage(user.getEmailAddress(), reminderMessage);  
  8.    }  

這個(gè)開發(fā)者可能會發(fā)現(xiàn)這個(gè)方法與之前的sendReminderMessage方法十分的相似。在這個(gè)情況下,他覺得他把驗(yàn)證功能與其他組件分開來的做法十分精明,看上去沒有必要為這短短兩行代碼重用之前的實(shí)現(xiàn)。

哪里錯(cuò)了呢?

這兩個(gè)方法看上去十分相似,但是又是不同的,使得開發(fā)者認(rèn)為是兩個(gè)不同的活動。這里有一種冗余的感覺,但還沒有造成問題。

 第四步:邏輯變更

從長遠(yuǎn)來看,越簡單的代碼會變的越復(fù)雜。在這個(gè)迭代后期,我們的開發(fā)者在sendReminderMessage方法中添加了一些更復(fù)雜的邏輯(預(yù)處理用戶名和校驗(yàn)郵箱地址)。

 
 
 
  1. public void sendReminderMessage(final IUser user) {  
  2.    String formattedUserName = formatUserNameForMessage(user.getName());  
  3.    String reminderMessage = this.messageGeneratorService.generateReminderMessage(formattedUserName);  
  4.    if (isEmailAddressValid(user.getEmailAddress()) {  
  5.       this.mailService.sendMessage(user.getEmailAddress(), reminderMessage);  
  6.    }  
  7. }  
  8.  
  9. public boolean isEmailAddressValid(final String emailAddress) { // 是否郵箱地址有效  
  10.    return emailAddress.contains('@');  
  11. }  
  12.  
  13. public String formatUserNameForMessage(final String userName) { // 為消息格式化用戶名  
  14.    return userName.toUpperCase();  

我們現(xiàn)在有了sendReminderMessage方法的新版本(雖然是一個(gè)很簡陋的驗(yàn)證系統(tǒng)),使得(曾經(jīng)相似的)UserReminderService變得相當(dāng)不同。

哪里錯(cuò)了呢?

用來給向用戶發(fā)送消息的過程發(fā)生了變化 (需要進(jìn)行校驗(yàn)). 由于該過程沒有包含在User類內(nèi)部,我們就必須追蹤它在所有不同形式下的所有實(shí)現(xiàn),然后對它們進(jìn)行修改。假設(shè)我們意識到SignupVerificationService也需要校驗(yàn),然后我們?yōu)樗砑恿诵r?yàn),我們?nèi)匀恍枰环N能夠重復(fù)使用這端校驗(yàn)代碼的方法.在需要校驗(yàn)的情況下,我們可能會把方法封裝到mailService中,但對于其他的邏輯,比如用戶姓名格式化,已經(jīng)被加入到不同的helper/service類中了,該怎么辦呢?這些代碼可能會被多個(gè)service類所需要,也可能只有一個(gè)service需要。

 
 
 
  1.        AbstractUserService  
  2.              /\  
  3.              |  
  4.              |  
  5.      ------------------------------------  
  6.     |                                  |  
  7. UserValidationService       UserReminderService 

與此同時(shí)另一個(gè)開發(fā)者也寫了另一個(gè)service,這個(gè)service是用來給某個(gè)Department實(shí)體(同樣也使用email地址)發(fā)送消息的.這位開發(fā)者想要使用AbstractUserService中的郵箱驗(yàn)證和名字格式化功能,但他的代碼是為Departments服務(wù)的,而不是Users,因此,代碼結(jié)構(gòu)中另一層又出現(xiàn)了:AbstractEntiryService.

哪里錯(cuò)了呢?

我們已經(jīng)失去了對我們程序結(jié)構(gòu)的控制,我們的開發(fā)團(tuán)隊(duì)開始發(fā)現(xiàn)很難再寫出干凈的代碼. 我們的類需要比實(shí)際需求更多的公共方法來維護(hù)復(fù)雜的類關(guān)系

 總結(jié)

通過貧血的領(lǐng)域模型來保持代碼結(jié)構(gòu)整潔并且可維護(hù)是當(dāng)然不可能的.然而,當(dāng)我們能夠使用充血領(lǐng)域模型的時(shí)候,維護(hù)代碼并且保持類接口簡潔就變得非常容易了.

 
 
 
  1. public class User {  
  2.    //Dependencies  
  3.    private IMailService mailService;  
  4.    private IMessageService messageService;  
  5.  
  6.    private final String name;  
  7.    private final String emailAddress;  
  8.  
  9.   public User(final String name, final String emailAddress) {  
  10.       this.name=name;  
  11.       this.emailAddress=emailAddress;  
  12.    }  
  13.  
  14.     public void sendReminderMessage() {  
  15.       deliverMessage( this.messageGeneratorService.generateReminderMessage(this.getName));  
  16.    }  
  17.  
  18.    public void sendVerificationEmail() {  
  19.       deliverMessage(this.messageGeneratorService.generateVerificationMessage(this.getName));  
  20.  
  21.    }  
  22.  
  23.    private void deliverMessage(final String message) {  
  24.       if (isEmailAddressValid(user.getEmailAddress()) {  
  25.          this.mailService.sendMessage(user.getEmailAddress(), reminderMessage);  
  26.       }  
  27.    }  
  28.  
  29.    public String getName() {  
  30.       return this.name;  
  31.    }  

注意,我們不再需要email地址的get方法,而且,如果你能原諒我玩數(shù)字游戲,我們增加了兩個(gè)User類的公共方法二不是引入兩個(gè)(至少)額外的類. 當(dāng)我們在適當(dāng)?shù)膶ο笊蠄?zhí)行方法的時(shí)候比在一個(gè)不自然的service對象上執(zhí)行方法看起來更直觀.

MailService和MessageServices仍被允許留在系統(tǒng)中因?yàn)樗鼈兊慕巧苊鞔_. 傳送郵件是一個(gè)清晰的架構(gòu)問題,應(yīng)該被從領(lǐng)域?qū)ο笾型ㄟ^接口(IMailService)抽象出來.生成消息應(yīng)該被如何抽象/封裝可能是更值得商榷的,但這篇文章就會比我與其的更長了.

我希望你會喜歡這篇文章.

英文原文:How Anaemic Domain Models Cause Bad Software

譯文鏈接:http://www.oschina.net/translate/how-anaemic-domain-models-cause-bad-software


名稱欄目:貧血領(lǐng)域模型是如何導(dǎo)致糟糕的軟件產(chǎn)生
網(wǎng)頁鏈接:http://www.5511xx.com/article/cdojppj.html