問題審查
正如@leanne說,你造型Subscription
,其專長是,比方說,MonthlySubscription
和ComplimentarySubscription
(給他們這個答案的名稱)。
你知道,訂閱可能過期:
- 對於
MonthlySubscription
,這種情況發生在用戶沒有支付當月的訂閱
- 對於
ComplimentarySubscription
,到期日期分配時,它的分配用戶
正如你可以看到一個ExpirationDate
任何Subscription
的本質屬性,但你保存它的方式是在每種情況下的不同。如果第一種情況你必須根據最後一個事件來計算它,在後者中你可以直接檢索它。
在數據庫
因此,與繼承處理,繪製該樣本模型數據庫模式,你可以在Martin Fowler的Patterns of Enterprise Application Architecture本書中描述的Class Table Inheritance模式去。這是它的意圖:
「表示類的繼承層次結構,每個類有一個表」。
基本上,您將擁有一個表格,其中的類別之間共有的屬性共享,並且您將在單獨的表格中存儲特定於每個類別的屬性。
牢記這一點,讓我們回顧一下你提出的方案:
- 有另一個表
complimentary_subscription
與用戶ID爲外鍵?
具有儲存ComplimentarySubscription
具體細節一個單獨的表聽起來不錯,但如果你不涉及這一塊與subscription
表,你可以同時具有MonthlySubscription
和ComplimentarySubscription
的用戶結束。它的外鍵應該指向subscription
表,該表可以告訴您用戶是否有訂閱(並且您必須強制每個用戶最多一次訂閱)。
- 記錄在
subscription
一個特殊的 「訂閱」 又在哪裏?
是的,你必須記錄一個用戶訂閱每月或免費。但是,如果您正在考慮像記錄一個數量爲零的特殊訂閱這樣的東西,那麼您正在尋找一種與您當前的設計相匹配的解決方案,而不是爲它尋找合適的模型(它可能並非如此)。
- 或添加其他列到他們的用戶排像
is_complimentary
和complimentary_expires_date
列?
我個人不喜歡這一個,因爲你把信息放在不屬於它的地方。考慮到這一點,您將在哪裏存儲免費訂閱的截止日期(請記住,對於每月的訂閱日期,您正在計算它,而不是存儲到期日期)?似乎所有這些信息都爲自己的「家」而哭泣。 另外,如果以後您需要添加一個新類型的訂閱,表格將開始混亂。
如果你這樣做,你必須每個subscription_event
得到改變的時間來處理數據同步(以包月的情況下)。通常我會盡量避免這種數據重複情況。
樣品溶液
我會做的添加新類型的訂閱時具有subscription
表來存儲MonthlySubscripton
和ComplimentarySubscription
之間共享信息,增加了type
列鍵時會讓你看好的可擴展性區分一行與哪種訂閱有關。
然後,將特定於每個訂閱類型的詳細信息存儲在其自己的表中,引用父行subscription
行。
用於檢索數據,你需要負責實例給出了subscription
行type
列值的正確類型的Subscription
的對象。
您可以查看「企業應用程序體系結構模式」一書中的模式,以獲取有關如何定義type
列值的進一步幫助,如何使用映射器對象執行實例化等。
01/03/2012更新:用於定義和處理type
列
這裏替代的澄清以下問題通過@enoinoc在評論中發佈更新:
特別是對於建議的type
列,這是否可以是指向描述不同類型訂閱的Plans
表的外鍵,例如前幾個月他們到期沒有付款。這聽起來合乎邏輯嗎?
在Plans
表中只要沒有靜態信息就不需要編輯就可以了。如果是這種情況,請不要過度概括您的解決方案,並將相關知識放入相應的Subscription
子類中。
關於外鍵的方法,我能想到的一些缺點會這樣的:
- 請記住,你的目標是要知道的
Subscription
至極子類在Plans
表中每行的。如果你得到的只是一個外鍵值(比如說一個整數),那麼你必須編寫代碼來將該值映射到要使用的類。這意味着額外的工作:)
- 如果你必須做不必要的額外工作,那很可能是因爲mainteinance會是一個痛苦:每當你添加一個新的計劃時,你都必須記住硬編碼它是外鍵值映射代碼。
- 如果數據庫導出/導入操作不正確,外鍵可能會更改。如果發生這種情況,您的映射代碼將不再起作用,您將不得不再次部署您的軟件(或至少,更改過的部分)。
建議的解決方案
我會做的是投入type
列在表Plans
。該列將保存知道如何從特定行構建正確Subscription
的類的名稱。
但是:爲什麼我們需要一個對象來構建每種類型的Subscription
?因爲您將使用來自不同表格(subscription_event
和complimentary_subscription
)的信息來構建每種類型的對象,並且隔離並封裝該行爲總是很好的。
讓我們來看看Plans
表可能看起來怎麼樣:
- 計劃表 -
ID |名稱|類型|其他色譜柱...
1 |每月| MonthlySubscriptionMapper
|
2 |免費| ComplimentarySubscriptionMapper
|
每個SubscriptionMapper
可以定義一個方法Subscription MapFrom(Row aRow)
從數據庫中取一排,並請您Subscription
子類(在本例MonthlySubscription
或ComplimentarySubscription
)的正確實例。
最後得到的type
列中指定的映射器的一個實例(不使用一個討厭的if
或case
語句),你可以從該列的值取類名,並通過使用反射,創建一個類的實例。
Hi @eoinoc。用戶獲得「免費訪問」訂閱意味着什麼?什麼屬性與正規訂閱有共同之處,以及歸因對於「免費訪問」是必不可少的? – nick2083 2012-01-01 04:58:15
@ nick2083這意味着我們可以爲他們提供會員級別的系統訪問權限,但是他們不需要付費,不像普通會員必須按月訂購。 – eoinoc 2012-01-01 10:10:39