對我而言,認識BLL層的作用,或者領域模型驅動的含義,最大的干擾來自數據庫。
我們很清楚的知道UI層的含義,也知道數據層是做什么的。但對於一個簡單的(甚至是相當復雜的)系統而言,實在不知道除了對數據庫進行增刪改查以外,還能做些什么?發布一篇博客,不就是在數據庫里插入一條記錄么?點擊一下推薦,不就是在數據庫里做一個update么?
為了避免數據庫的干擾,這里,我們設定:不使用關系數據庫做存儲!請大家牢記,為了更清晰,更深刻的認識到這一點,我們再次明確,我們將使用最流行的NoSQL技術。牛叉吧!興奮吧?
打滿了雞血吧!
好的,設計的任務交給你了,小李同學。
接下來,你怎么辦?哎呀,我對NoSQL還不熟呀(不熟?其實除了名字知道以外,其他什么都根本就不知道)。馬上開始研究一下NoSQL,看看里面有沒有什么庫呀,表呀之類的,好像那里面用的是集合?
如果你這樣走下去的話,就偏離了DDD的宗旨了(但也不能說你“錯”了)。
我是這樣做的。
問:這個系統要做什么?有哪些功能?
答:發布博客,博客可以評論。可以提問題,回答問題。當然,做這些事,都得注冊登錄……
好,根據以上信息,我們可以抽象出這幾個對象。
這是一個良好的開端。再細致點,博客和問題,都必須有標題;而博客的評論和問題的答案,不需要標題;但不管是博客還是問題,評論還是回答,都會有一個作者,都要發布時都要記錄下
發布的時間,甚至發布者的IP(基於中國人都知道的原因)。博客和問題,還要記錄下瀏覽量……
到這里,你是不是嗅到了一種什么味道?“不管……還是……都……”,共同的東西!那么想到面向對象的三大特征,“繼承”就呼之欲出了。所以我們通過抽象,得到了以下的對象。
View Code
我們很清楚的知道UI層的含義,也知道數據層是做什么的。但對於一個簡單的(甚至是相當復雜的)系統而言,實在不知道除了對數據庫進行增刪改查以外,還能做些什么?發布一篇博客,不就是在數據庫里插入一條記錄么?點擊一下推薦,不就是在數據庫里做一個update么?
為了避免數據庫的干擾,這里,我們設定:不使用關系數據庫做存儲!請大家牢記,為了更清晰,更深刻的認識到這一點,我們再次明確,我們將使用最流行的NoSQL技術。牛叉吧!興奮吧?
打滿了雞血吧!
好的,設計的任務交給你了,小李同學。
接下來,你怎么辦?哎呀,我對NoSQL還不熟呀(不熟?其實除了名字知道以外,其他什么都根本就不知道)。馬上開始研究一下NoSQL,看看里面有沒有什么庫呀,表呀之類的,好像那里面用的是集合?
如果你這樣走下去的話,就偏離了DDD的宗旨了(但也不能說你“錯”了)。
我是這樣做的。
問:這個系統要做什么?有哪些功能?
答:發布博客,博客可以評論。可以提問題,回答問題。當然,做這些事,都得注冊登錄……
好,根據以上信息,我們可以抽象出這幾個對象。
這是一個良好的開端。再細致點,博客和問題,都必須有標題;而博客的評論和問題的答案,不需要標題;但不管是博客還是問題,評論還是回答,都會有一個作者,都要發布時都要記錄下
發布的時間,甚至發布者的IP(基於中國人都知道的原因)。博客和問題,還要記錄下瀏覽量……
到這里,你是不是嗅到了一種什么味道?“不管……還是……都……”,共同的東西!那么想到面向對象的三大特征,“繼承”就呼之欲出了。所以我們通過抽象,得到了以下的對象。

///
<summary>
/// Article is abstract, means it's not a really entity
/// </summary>
public abstract class Article : Entity< int>
{
#region Properties
#region Content
public virtual string Body { get; set; }
#endregion
#region Log
/// <summary>
/// Need not set manually in most scenarios
/// </summary>
public virtual string PublishIP { get; set; }
/// <summary>
/// Need not set manually in most scenarios
/// </summary>
public virtual DateTime? LastModifiedTime { get; set; }
#endregion
#region Associates
public virtual User Author { get; set; }
#endregion
#endregion
#region Public Methods
public virtual void Publish()
{
#region set some default value
setCreatedTime();
setLastModifiedTime();
setPublishIP();
#endregion
}
#endregion
#region Protect Methods
protected virtual void setLastModifiedTime()
{
if (LastModifiedTime == null)
{
LastModifiedTime = DateTime.Now;
}
}
protected virtual void setPublishIP()
{
if ( string.IsNullOrEmpty(PublishIP))
{
PublishIP = HttpContext.Current.Request.UserHostAddress;
}
}
#endregion
}
/// <summary>
/// represent article can be regarded as the main part of one page, e.g. Blog and Question
/// </summary>
public abstract class MainArticle : Article
{
#region Properties
#region Content
public virtual string Title { get; set; }
public virtual string Keywords { get; set; }
#endregion
#region Credit
public virtual int ViewCount { get; set; }
#endregion
#region Log
#endregion
#endregion
#region Methods
public virtual void View()
{
ViewCount++;
}
#endregion
}
public class Blog : MainArticle
{
#region Properties
#region Associates
public virtual CategoryOfBlog Category { get; set; }
#endregion
#region Content
public virtual string BlogAbstract { get; set; }
#endregion
#endregion
}
public class CommentOfBlog : AttachedArticle
{
#region Properties
#region Associates
public virtual Blog ReferredBlog { get; set; }
public virtual CommentOfBlog ReferredComment { get; set; }
#endregion
#endregion
}
public abstract class AttachedArticle : Article
{
}
public class Answer : AttachedArticle
{
#region Properties
#region Associates
public virtual Question ReferredQuestion { get; set; }
public virtual Answer ReferredAnswer { get; set; }
#endregion
#endregion
}
/// Article is abstract, means it's not a really entity
/// </summary>
public abstract class Article : Entity< int>
{
#region Properties
#region Content
public virtual string Body { get; set; }
#endregion
#region Log
/// <summary>
/// Need not set manually in most scenarios
/// </summary>
public virtual string PublishIP { get; set; }
/// <summary>
/// Need not set manually in most scenarios
/// </summary>
public virtual DateTime? LastModifiedTime { get; set; }
#endregion
#region Associates
public virtual User Author { get; set; }
#endregion
#endregion
#region Public Methods
public virtual void Publish()
{
#region set some default value
setCreatedTime();
setLastModifiedTime();
setPublishIP();
#endregion
}
#endregion
#region Protect Methods
protected virtual void setLastModifiedTime()
{
if (LastModifiedTime == null)
{
LastModifiedTime = DateTime.Now;
}
}
protected virtual void setPublishIP()
{
if ( string.IsNullOrEmpty(PublishIP))
{
PublishIP = HttpContext.Current.Request.UserHostAddress;
}
}
#endregion
}
/// <summary>
/// represent article can be regarded as the main part of one page, e.g. Blog and Question
/// </summary>
public abstract class MainArticle : Article
{
#region Properties
#region Content
public virtual string Title { get; set; }
public virtual string Keywords { get; set; }
#endregion
#region Credit
public virtual int ViewCount { get; set; }
#endregion
#region Log
#endregion
#endregion
#region Methods
public virtual void View()
{
ViewCount++;
}
#endregion
}
public class Blog : MainArticle
{
#region Properties
#region Associates
public virtual CategoryOfBlog Category { get; set; }
#endregion
#region Content
public virtual string BlogAbstract { get; set; }
#endregion
#endregion
}
public class CommentOfBlog : AttachedArticle
{
#region Properties
#region Associates
public virtual Blog ReferredBlog { get; set; }
public virtual CommentOfBlog ReferredComment { get; set; }
#endregion
#endregion
}
public abstract class AttachedArticle : Article
{
}
public class Answer : AttachedArticle
{
#region Properties
#region Associates
public virtual Question ReferredQuestion { get; set; }
public virtual Answer ReferredAnswer { get; set; }
#endregion
#endregion
}

這樣做的好處,很明顯的,就是減少了重復代碼。“代碼越少越好”,我深以為然。當然,隨之而來,還有其他好處,容后再表,呵呵。這里只說一句,良好的抽象是實現設計模式的基礎。
其實,只要有面向對象的思想,進行這樣的抽象是相當容易的(這樣的抽象也是不對的,以后再論述)。但我們常常會被關系型數據庫所干擾(尤其是有一定開發經驗的程序員),而不敢進行這種“大膽的”抽象。因為即使將代碼寫到這里了,也得面臨一個很現實的問題,接下來怎么辦?最終我們怎么把這些對象持久化(保存到數據庫或其他媒介中去)。這就是我們接下來要進行的工作了。
最后,對那些還想着數據庫的同學,再重復強調一點:這個項目,我們用NoSQL!哦,sorry,改主意了,大家反映NoSQL太難了,又說干脆用xml文件吧。