關鍵的區別在於在Sanderson圖中包含了「演示模型」。 ASP.NET MVC的實現經常使用模型作爲表示模型,即使它們可能不同(我認爲它們應該是不同的,但這是一場神聖的戰爭,沒有必要深入)。
在大多數非常簡單的ASP.NET MVC應用程序中,模型是數據實體。無論是EF實體還是Linq2Sql實體,都沒有區別。這是因爲大多數應用程序都是簡單的form-over-data,並且表示可能與持久性是一對一的。
但是,MVC模式本身不需要這個。在一個更純粹的框架無關形式中,Sanderson的圖表說明了控制器正在與模型進行交互的事實。從這個意義上說,這個模型實際上是「通往域核心的門戶」。控制器和視圖是應用程序的一部分,但是該模型具有底層業務邏輯,在其下面還有持久層和其他基礎架構信息層(當然,這些信息是分開的),這些信息對於應用程序來說是未知的。控制器和模型之間的邊界是應用程序邊界,即其他應用程序也可以連接到域核心並與之交互的點。
演示模型通常只不過是一個簡單的值對象。從某種意義上說,它不是一種實體,它不必展示任何商業行爲,也不必像持久的商業實體那樣維持其生命週期。它只是一個具有一些數據屬性的平面對象。
它可以有一些的行爲,但該行爲是爲應用程序而不是域核心。例如,也許它有一些視圖可以使用的方法或屬性。演示模型是應用程序的一部分,所以它是表示層意識。本質上它只是保存控制器需要傳遞給視圖的數據(甚至根據框架甚至從請求中接收數據)。
在ASP.NET MVC中,您經常會將該模型用作演示模型。在這些情況下,同一個對象可能扮演兩種角色,但這兩種角色是完全不同的。
編輯:只注意到你的更新問題...
在這個例子中,Album
是打兩域模型和展示模型的作用。 (事實上,我認爲它不是一個領域模型,因爲它太貧乏了。請注意,它沒有功能,只是裸露的數據。)在更豐富的領域模型中,Album
可能會有更多的功能。對於一個人爲的例子,想象一下,不是自動實現的屬性,而是它具有在設置時強制執行業務邏輯的屬性,並且它具有方法,例如AddSong(Song song)
和Play()
以及其他這樣的行爲。
這個更豐富的模型仍然可以用作演示模型,但功能在視圖範圍內可能沒有意義。一個視圖更適合僅僅是裸露的數據元素。控制器將與模型的功能進行交互。因此,您可以在結構中創建一個類似於Album
域模型的演示模型,並且它看起來就像您示例中的模型。未來,如果視圖還需要其他數據呢?也許該視圖需要了解其他模型的一些內容,這些模型不屬於與Album
相同的聚合體。修改域模型以適應視圖是沒有意義的。這是倒退。演示文稿應該圍繞域核心而不是其他方式。因此,您可以將屬性添加到演示模型中,這些屬性是從控制器中的其他內容填充的。
所以,你可能最終得到這樣的事情...
領域模型:
public class Album
{
public int ID { get; private set; } // might need to be immutable
private string _title;
public string Title
{
get { return _title; }
set
{
// don't allow empty titles
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentNullException("Title");
_title = value;
}
}
private Album() { }
public Album(int id, string title)
{
ID = id;
Title = title;
}
public void Play()
{
// some implementation
}
public void SomeOtherMethod()
{
// some implementation
}
}
隨着業務領域的發展和變化,這種模式可能會隨之改變。主要的一點是它根據域名核心和業務邏輯的要求而改變,而不是根據UI實現的要求。
使用該域核心的特定網站上的特定「頁面」可能需要關於專輯的特定信息,並且可能還需要其他一些信息。你會定製的演示模型,以適應這些,那麼
public class AlbumViewModel
{
public int ID { get; set; }
public string Title { get; set; }
public string Owner { get; set; }
public IEnumerable<Listener> Listeners { get; set; }
public string SomeCompletelyUnrelatedValueNeededByTheView { get; set; }
}
控制器將構建此演示模型視圖:
public ActionResult Details(int id)
{
// TODO: validate and sanitize any inputs
var album = AlbumRepository.Get(id); // after all, why bind the UI _directly_ to the DB? that's just silly
var someOtherObject = SomeOtherRepository.Get(someOtherValueFromSomewhereElse);
var albumVM = new AlbumViewModel
{
ID = album.ID,
Title = album.Title,
Owner = somethingElse.SomeValue,
Listeners = someOtherObject.GetListeners(album),
SomeCompletelyUnrelatedValueNeededByTheView = "foo"
};
return View(albumVM);
}
這是整個一個更手動方法。當您有更復雜的領域模型,與該領域交互的多個複雜應用程序,遍及整個領域的不同技術堆棧等等時,這非常有用。對於簡單的數據形式應用程序,標準的ASP.NET MVC實現通常工作正常。大多數教程都反映了這一點,將多個職責合併爲更少的對象,使用裝飾器代替顯式代碼(假設使用相同的工具堆棧)等。
您正在查看的示例使用非常少的代碼就可以快速獲得一個可用的應用程序。就像任何框架一樣,如果你按照框架的意願去做,那麼它就可以很好地工作。如果您需要需要以超出框架的範圍,您仍然可以以更抽象且與框架無關的方式維護該模式。
編輯:再次您的更新...
從某種意義上說,是的。 ASP.NET MVC是一個借鑑MVC模式的框架。與所有事情一樣,有不止一種方法可以做到這一點。堅持簡單的實現和快速的應用程序,由ASP.NET MVC框架提供的功能,並在其各種教程中解釋是完全可以接受的,並且是使用框架的一個很好的例子...使用工具完成工作。
他們堅持所有最有意義的方式。然而,與此同時,在框架的真實性質中(它通常超出了模式描述的範圍),它們試圖給你一些工具,使得實際開發工作變得非常輕鬆。如果您沒有迫切需要將您的域模型與演示文稿模型分開,則不需要。一個模型可以扮演兩種角色。如果您沒有迫切需要將數據訪問抽象化,比如存儲庫模式,那麼您不必這樣做。您可以將一些快速的實體框架功能直接放在您的模型中,並完成它。
最終它取決於項目的需求,開發人員的喜好等等。模式更具學術性,框架更實用。平衡兩者是關鍵。
根據你的編輯,我已經更新了我的答案:) – David 2012-07-25 20:40:37