成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

貧血領域模型是如何導致糟糕的軟件產生

開發 后端 開發工具
使用貧血領域模型通常被認為是一種反模式,因為它鼓勵程序員無意義地重復編寫代碼。下面我將簡短(而瑣碎)地用一個例子來闡述這個是如何產生的。我們可以通過細致的規劃以及嚴格的編碼規范來避免其發生,但是同樣可以獲得較好的封裝。防止陷入貧血領域模型深坑的難度隨項目人數呈指數級增長。

使用貧血領域模型通常被認為是一種反模式,因為它鼓勵程序員無意義地重復編寫代碼。下面我將簡短(而瑣碎)地用一個例子來闡述這個是如何產生的。我們可以通過細致的規劃以及嚴格的編碼規范來避免其發生,但是同樣可以獲得較好的封裝。防止陷入貧血領域模型深坑的難度隨項目人數呈指數級增長。

我相信所有人對面向對象都有所認識,但我卻有趣地發現一些看似毫無意義的小舉措卻導致了最終一場大災難。

 第一步:編寫貧血實體

在軟件開發的某些情況下,我們會在一個領域實體之外實現一些邏輯。這可能是由于一個明確的設計決定或者,更有可能,持久類不能引用外部服務造成了不能將這段邏輯實現在領域對象的內部。把外部服務(依賴)添加到實體對象中將會造成與數據庫的交互變的復雜而晦澀難懂。

  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.    }  

 第二部:邏輯被實現在外部類中

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

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

這個并不能實現在User實體中,因為我們根本無法在實體中取得郵件服務或者是消息生成器。到目前為止,這個看起來還不算很糟糕(我們很好地封裝了消息的創建以及郵件發送過程),但是這僅僅是“敗壞”的開始,然后馬上開始讓這些不警惕的開發者陷入災難。

哪里錯了呢?

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

 

 第三步:重復代碼產生

在此期間,另一個開發者開發了一個全新的組件,同樣也使用了User實體。這個新的服務被用來決定注冊用戶是真的用戶而不是一個機器人。

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

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

哪里錯了呢?

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

 

 第四步:邏輯變更

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

  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();  

我們現在有了sendReminderMessage方法的新版本(雖然是一個很簡陋的驗證系統),使得(曾經相似的)UserReminderService變得相當不同。

哪里錯了呢?

用來給向用戶發送消息的過程發生了變化 (需要進行校驗). 由于該過程沒有包含在User類內部,我們就必須追蹤它在所有不同形式下的所有實現,然后對它們進行修改。假設我們意識到SignupVerificationService也需要校驗,然后我們為它添加了校驗,我們仍然需要一種能夠重復使用這端校驗代碼的方法.在需要校驗的情況下,我們可能會把方法封裝到mailService中,但對于其他的邏輯,比如用戶姓名格式化,已經被加入到不同的helper/service類中了,該怎么辦呢?這些代碼可能會被多個service類所需要,也可能只有一個service需要。

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

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

哪里錯了呢?

我們已經失去了對我們程序結構的控制,我們的開發團隊開始發現很難再寫出干凈的代碼. 我們的類需要比實際需求更多的公共方法來維護復雜的類關系

 

 總結

通過貧血的領域模型來保持代碼結構整潔并且可維護是當然不可能的.然而,當我們能夠使用充血領域模型的時候,維護代碼并且保持類接口簡潔就變得非常容易了.

  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方法,而且,如果你能原諒我玩數字游戲,我們增加了兩個User類的公共方法二不是引入兩個(至少)額外的類. 當我們在適當的對象上執行方法的時候比在一個不自然的service對象上執行方法看起來更直觀.

MailService和MessageServices仍被允許留在系統中因為它們的角色很明確. 傳送郵件是一個清晰的架構問題,應該被從領域對象中通過接口(IMailService)抽象出來.生成消息應該被如何抽象/封裝可能是更值得商榷的,但這篇文章就會比我與其的更長了.

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

 

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

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

責任編輯:林師授 來源: OSCHINA編譯
相關推薦

2022-02-16 09:29:06

領域模型貧血模型充血模型

2019-08-29 07:04:29

網絡延遲IP網絡

2015-08-31 10:14:30

程序員處理代碼糟糕代碼

2015-09-01 11:20:58

程序員糟糕代碼

2019-01-09 08:00:30

數據中心配置物理服務器

2021-01-05 13:45:31

Go語言編程語言

2018-05-18 10:35:56

云計算差異技術

2023-02-20 14:44:22

DDD領域模型

2021-08-02 08:21:53

Python編程語言開發

2022-06-27 10:41:46

交通領域物聯網大數據

2024-07-10 11:40:15

2021-07-14 10:09:05

架構模型數據

2023-02-08 07:04:20

死鎖面試官單元

2023-01-09 08:00:41

JavaScript閉包

2023-12-08 11:22:31

IT首席轉型官轉型

2020-11-18 08:33:24

CommonJSJava

2013-09-05 10:33:09

福布斯微軟諾基亞

2018-02-25 11:00:34

代碼開發程序員

2012-07-16 09:41:59

項目
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一区二区三区日 | 亚洲一区久久 | 亚欧精品一区 | 亚洲精品区 | 亚洲精选一区二区 | www.操.com | 91传媒在线观看 | 亚洲高清av| 亚洲精品一区二区在线观看 | 黄网站免费入口 | 国产免费看| 日韩一区二区三区av | 久久狠狠| 国产精品久久久久久久久久久久久 | 亚洲精品一 | 国产成人精品午夜视频免费 | 国产精品一区视频 | 精品一二区 | 日韩黄a | www.4虎影院 国产999精品久久久影片官网 | 欧美乱淫视频 | 欧美黑人巨大videos精品 | 另类二区| 日本精品久久久久久久 | www.日本在线观看 | 久久久久久久久一区 | 欧美精品久久久久久久久老牛影院 | 亚洲精品18 | 天天操精品视频 | 午夜av电影院| 99久久婷婷国产综合精品电影 | 一区二区三区免费在线观看 | 欧美中文字幕一区二区三区亚洲 | 日韩在线高清 | 中文字幕免费观看 | k8久久久一区二区三区 | 91高清在线| 成人午夜电影网 | 午夜免费福利电影 | 黄色在线| 视频一区在线 |