2013-05-02 70 views
28

使用MVVM模式做了幾個項目之後,我還在與視圖模型的角色掙扎:MVVM:視圖模型和業務邏輯連接

我所做的過去: 使用模型只是作爲數據容器。 將邏輯放在ViewModel中操縱數據。 (這就是業務邏輯的權利?) Con:邏輯不可重用。

我現在要做的是: 保持ViewModel儘可能薄。 將所有邏輯移入模型層。 只保留ViewModel中的演示邏輯。 Con:如果數據在模型層內發生更改,令UI通知非常痛苦。

所以我給你舉個例子,以使其更清晰的:

場景: 工具來重命名文件。 類: 文件:代表每個文件;規則:包含邏輯如何重命名文件;

如果我遵循以下方法1: 爲文件,規則和視圖 - > RenamerViewModel創建ViewModel。 將所有邏輯放入RenamerViewModel: 包含FileViewModel和RuleViewModel的列表以及前進邏輯。 簡單快捷,但不可重複使用。

如果我遵循方法2: 創建一個新的模型類 - > Renamer,其中包含文件列表,規則和前進的邏輯,以遍歷每個文件並應用每個規則。 爲文件,規則和重命名創建視圖模型。 現在,RenamerViewModel只包含Renamer Model的一個實例,外加兩個ObservableCollections來包裝Renamer的File和Rule List。 但整個邏輯是在Renamer模型中。因此,如果觸發Renamer模型以通過方法調用來操作某些數據,則ViewModel不具有處理數據的線索。 因爲模型不包含任何PropertyChange通知,我會避免這種情況。因此,商業和演示邏輯是分離的,但這使得很難通知用戶界面。

回答

34

將視圖模型內部的業務邏輯放在視圖模型中是一種非常糟糕的做事方式,所以我很快就會說從來沒有做過並繼續討論第二種選擇。

將邏輯放在模型內更合理,這是一個很好的開始方法。有什麼缺點?你的問題說

因此,如果更名型號被觸發通過方法來操縱某些數據 呼叫,視圖模型完全不知道哪個數據進行操作。因爲 模型不包含任何PropertyChange通知,我會 避免這一點。

那麼,讓你的模型執行INotifyPropertyChanged肯定會讓你繼續前進到更好的東西。但是,確實有時不可能這樣做 - 例如,模型可能是一個部分類,其中屬性是由工具自動生成的,並且不會引發更改通知。這是不幸的,但不是世界末日。

如果你想買東西然後有人必須支付它;如果它不是,讓這樣的通知,那麼你只剩下兩種選擇模式:

  1. 視圖模型知道的模型,其操作(可能)原因的變化,它每個這樣的操作之後更新其狀態。
  2. 其他人知道哪些操作會導致更改,並且他們通知視圖模型在包裝模型更改後更新其狀態。

第一個選項再次是一個壞主意,因爲實際上它會回到在視圖模型中放入「業務邏輯」。還不如在視圖模型中放入全部業務邏輯,但仍然如此。

第二個選項是更有前途(不幸的是更多的工作):在一個單獨的類業務邏輯的

  • 戴上部分(「服務」)。該服務將通過適當地處理模型實例來實現您希望執行的所有業務操作。
  • 這意味着服務知道模型屬性何時可能會改變(這是OK:model + service ==業務邏輯)。
  • 該服務將向所有相關方提供有關更改模型的通知;你的視圖模型將依賴於服務並接收這些通知(以便他們知道什麼時候「他們的」模型已被更新)。因爲業務操作也是由服務實現的,所以這仍然是非常自然的(例如,當在視圖模型上調用命令時,反應會調用服務的適當方法;請記住,視圖模型本身並不知道業務邏輯)。

有關這種實現的更多信息,請參閱我的答案herehere

+1

通知事物總是被描述爲ViewModel部分,這就是爲什麼我會在模型中避免它。感覺就像兩次做同樣的事情。 – JDeuker 2013-05-02 13:45:35

+1

@ J.D .:當然,但不是要實施的服務。你的來電。 – Jon 2013-05-02 14:00:37

+0

@Jon:+1表示「永遠不會那樣」。習慣於N層模型的開發人員往往會忘記向VM添加WPF庫引用,以便交還需要組合的複雜對象,如FlowDocument。 – 2013-11-06 19:20:49

10

這兩種方法都是有效的,但還有第三種方法:在模型層和VM層之間實現服務。如果您希望保持模型不變,服務可以提供一個UI無關的中間人,可以以可重用的方式強制實施您的業務規則。

,因爲模型犯規包含任何的PropertyChange通知,我會避免

你爲什麼要避免這種?不要誤解我的意思,我傾向於儘可能保持模型的愚蠢,但在模型中實施更改通知有時可能會有用,而且您只需在System.ComponentModel上執行相關操作即可。這完全是UI不可知的。

+0

服務是否使用Model或ViewModel實例? – JDeuker 2013-05-02 13:28:27

+0

@ J.D .:模型 - 從服務層不存在對視圖層的依賴。您可以將服務層視爲增強並保護模型層的完整性。 – 2013-05-02 13:41:48

0

您也可以在Model和ViewModel上實現IDataErrorInfo,但僅在Model中進行驗證,這將簡化您在僅在Model中實現業務規則的方式...

例:

視圖模型:

... 

private Person person; 

... 

string IDataErrorInfo.this[string propertyName] 
{ 
    get 
    { 
     string error = (person as IDataErrorInfo)[propertyName]; 
     return error; 
    } 
} 

型號:

public class Person:INotifyPropertyChanged,IDataErrorInfo 
{ 

... 

    string IDataErrorInfo.this[string propertyName] 
    { 
     get { return this.GetValidationError(propertyName); } 
    } 

... 

    string GetValidationError(string propertyName) 
    { 
     if(propertyName == "PersonName") 
      //do the validation here returning the string error 
    } 
} 

另外看看在MVCVM模式,即時通訊真正使用它,它是相當優良抽象業務邏輯到控制器類而不是模型或視圖模型

1

我做了以下

  1. 查看與處理點擊處理程序,並創造新的視圖模型XAML視圖邏輯只

  2. 視圖模型。處理路由事件等。

  3. 模型,這是我的數據容器和關於驗證模型數據的業務邏輯。

  4. 用數據填充模型的服務。例如,調用Web服務器,從磁盤加載它,保存到磁盤等。根據示例,我的模型和服務通常都會實現IPropertyChanged。或者他們可能有事件處理程序。

任何複雜的應用程序需要另一個層。我稱之爲model + service,view,viewmodel。該服務抽象您的業務邏輯並將模型實例作爲依賴項或創建模型。