參照QQ郵箱,設計一款簡易版的站內信

在學習軟件編程的第一天,老師就告訴我們:程序 = 數據結構 + 算法。在使用一款應用時,我們只能看到頁面上展示的內容,並不知道其背後的數據結構,更不知道使用了什麼算法。

在寫程序時,其實涉及到兩種數據結構,一種是程序運行時,數據在內存裏的存儲結構,這和使用的開發語言有關;另一種是數據存放在數據庫裏的數據結構,和數據庫有關,也和數據表設計有關。

這裏所說的數據結構,是存儲在數據庫裏的數據結構,現在用的數據庫大部分都是關係型數據庫。現在,要做一個類似於QQ郵箱的站內信,該如何設計呢?

簡要描述一下站內信的業務需求:

  1. 發送郵件給一個用戶或多個用戶;
  2. 接收到郵件後,可以回覆郵件;
  3. 可以對一封郵件溯源,查看一封郵件的歷史往返記錄;
  4. 對郵件的狀態進行標註,未讀的、已讀的、已發送的;
    備註說明:發生郵件和回覆郵件均可以上傳圖片,最多五個;每個用戶可以清楚地看到未讀、已讀、已發送郵件列表;

發送郵件是需要郵箱服務器發送的,這裏的應用場景是站內信,那麼站內信的系統就可以充當郵箱服務器的功能。

首先看看,在QQ郵箱上創建一封郵件時,頁面上需要哪些元素:


在郵件創建頁面,大致需要以下這些字段屬性:
1)接收人
2)郵件標題
3)郵件正文
4)附件
5)發送人,默認當前登錄用戶

接下來,開始設計主表,站內信信息表的初步的設計如下圖所示:


只有站內信一個主表貌似不夠用,接收郵件的用戶,有可能是一個,也有可能是多個;接收人有的查看了郵件,有的還沒有查看郵件;那麼每個接收人對郵件的閱讀狀態可就不一樣了,這個該怎麼處理呢?

郵件的發送人,只有一個,這個是可以保證不變的,那麼郵件的發送人就可以作爲郵件信息表的字段來存儲。接收人是多個,每個人的閱讀狀態又不同,那麼這個可以單獨設計爲一個表,每個接收人作爲一條獨立的記錄存在;其關係圖如下所示。

站內信和發件人的關係,一個站內信只能有一個發件人;一個用戶卻可以發送多封郵件;站內信和用戶是多對一的關係;
站內信和收件人的關係,一個站內信可能有一個或一個以上的接收人;一個用戶是多個站內信的接收人;站內信和收件人,是多對多的關係;
每個接收人所接收的郵件默認爲未讀狀態,在用戶讀過之後,變成已讀狀態,不會影響其他用戶郵件的閱讀狀態。

那麼有人會看到,郵件裏漏掉了附件這個字段呀?

是的,沒錯,郵件裏沒有附件,爲何沒有附件?

因爲附件有可能上傳多個,雖然也有數量限制,但是你想,如果把這個字段放在主表裏,最多限制五個,你就需要在主表裏加入五個附件的字段,不管用戶有沒有上傳五個附件,都需要數據庫把這個空間開闢出來空在那裏,這是資源浪費呀。

沒錯,這裏會把附件最爲一個單獨的表來設計,作爲一個附屬表來設計,附屬於郵件信息這個主表;

這樣設計附件好處很明顯,用戶上傳一個附件,增加一個附件的存儲空間,沒有上傳過附件,就不需要開闢多餘的空間。
一封郵件可能有零個或多個附件,一個附件只屬於一封站內信,站內信和附件是一對多的關係。

接下來還有一個問題需要解決,如何追蹤一封郵件的歷史往返記錄,就像QQ郵箱一樣?

這個也好辦,一封郵件可以有零個或一個父郵件,第一次創建的郵件是沒有父郵件的,每次被回覆的郵件都有一個父郵件;並且,一個郵件就只能有一個父郵件;在查看一封郵件的時候,就可以根據它的父郵件往上追蹤過往的郵件,其設計圖如下所示:


接下來把這個CDM設計圖轉化爲PDM設計圖,看看數據結構是不是我們想要的樣子,關係上對應的對不對!



把主表中衝突的email_uid改爲父email_uid,主表中的用戶uid指向發件人,附件表的郵件uid指向主表的郵件uid,郵件與收件人的關聯關係表分別指向郵件和用戶,關聯關係沒有錯,非常完美。

接下來,再做一點特殊的需求,每個用戶都有所屬企業,用戶不僅可以給用戶發郵件,也可以給某一個企業或多個企業發郵件,還可以發給全部的用戶;如果是給某個企業發送的郵件,那麼這個企業下的所有用戶都能接收到,這個該如何設計呢?

先增加企業表的設計,再關聯一下企業與用戶的關係,一個企業下面可能有多個用戶,一個用戶只能屬於一家企業,企業與用戶是一對多的關係,如下圖所示:


由於郵件的接收者可以是企業,所以在主表中增加一個冗餘字段,用於標識這個郵件是發給企業的,還是發給企業下的某個人,還是發送給全部用戶;在主表中增加一個接收人類型,默認0,默認0,0:全部,1:企業,2:用戶,如下圖所示:


接收者這邊該如何處理呢?

同樣地,也在關係表中增加企業的唯一標識符做關聯,如果是發送給企業的,那麼接收人那一列空着,當企業下的用戶登錄時,將能看到發送給這個企業的郵件,該用戶閱讀完畢後,再往關係表中增加一條已讀的記錄,如下圖所示:


也就是說,站內信發給所有用戶的時候,是不需要填充關係表的,只需要根據主表的接收者類型來判斷,接收者類型爲0又不是自己發送的,則處於未閱讀狀態。

如果接收人是一個或多個企業,那麼只會在關係表中新增站內信和企業的關聯關係,企業用戶登錄後,也根據接收者類型和企業uid來獲取未讀的郵件。

如果接收人是一個或多個用戶,那麼就會在關係表中新增站內信和接收者的未讀狀態的關聯關係,用戶登錄後,根據接收者類型和未讀狀態來獲取未讀郵件。

未讀郵件的檢索最複雜,需要三種複合條件的判斷。

已讀郵件就比較簡單了,主表關聯關係表,狀態爲已讀的,就是已讀的數據。

已發送郵件最簡單,根據發送人檢索便可。

在查看某一封郵件,根據父類郵件uid去獲取上一封郵件,有父類郵件uid就遞歸獲取,直到父類uid沒有爲止,無意中發現是這樣有意思的一個圖:


作爲一款簡單的站內信設計,相信這些功能已經足夠用了,不夠用再加吧,哈哈。臨需而變喲~!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章