2009-06-10 40 views
14

Tôi tự hỏi về cách tiếp cận kế thừa với Mô hình Xem trong mẫu MVVM. Trong ứng dụng của tôi, tôi có một mô hình dữ liệu tương tự như sau:Thừa kế MVVM với Mô hình Xem

class CustomObject 
{ 
    public string Title { get; set; } 
} 

class CustomItem : CustomObject 
{ 
    public string Description { get; set; } 
} 

class CustomProduct : CustomItem 
{ 
    public double Price { get; set; } 
} 

Trong ứng dụng của tôi, tôi có một lớp ViewModelBase và sau đó sẽ có các View Models sau:

  • CustomObjectViewModel
  • CustomItemViewModel
  • CustomProductViewModel

Thực hiện thô n của CustomObjectViewModel sẽ giống như sau:

class CustomObjectViewModel : ViewModelBase 
{ 
    private readonly CustomObject _customObject; 

    public CustomObjectViewModel(CustomObject customObject) 
    { 
     _customObject = customObject; 
    } 

    public string Title 
    { 
     // implementation excluded for brevity 
    } 
} 

Nó có vẻ hợp lý với tôi rằng Xem Models của tôi sẽ mở rộng bản thân theo cách tương tự như mô hình của tôi đã làm (CustomItemViewModel kéo dài CustomObjectViewModel và vân vân). Tuy nhiên, tôi đã nhận thấy rằng khi tôi đi xuống cây thừa kế, tôi sẽ thêm các tham chiếu bổ sung cho cùng một đối tượng. Điều này có vẻ khá quá mức với tôi và đã tự hỏi làm thế nào để tiếp cận vấn đề này và nếu nó có thể làm cho nó sạch hơn nhiều.

Trả lời

17

Nói chung tôi muốn giới thiệu bạn không được thừa kế giữa các lớp ViewModel khác nhau, nhưng thay vào đó để chúng kế thừa trực tiếp từ lớp cơ sở trừu tượng chung.
Điều này là tránh giới thiệu sự phức tạp không cần thiết bằng cách gây ô nhiễm giao diện của lớp ViewModel với các thành viên đến từ cấp cao hơn trong phân cấp, nhưng không hoàn toàn cố kết với mục đích chính của lớp.
Các khớp nối đi kèm với thừa kế cũng sẽ có thể làm cho nó khó khăn để thay đổi một lớp ViewModel mà không ảnh hưởng đến bất kỳ lớp học có nguồn gốc của nó.

Nếu lớp ViewModel của bạn sẽ luôn luôn tham khảo một đối tượng mẫu duy nhất, bạn có thể sử dụng Generics để đóng gói quy tắc này vào lớp cơ sở:

public abstract class ViewModelBase<TModel> 
{ 
    private readonly TModel _dataObject; 

    public CustomObjectViewModel(TModel dataObject) 
    { 
     _dataObject = dataObject; 
    } 

    protected TModel DataObject { get; } 
} 

public class CustomObjectViewModel : ViewModelBase<CustomObject> 
{ 
    public string Title 
    { 
     // implementation excluded for brevity 
    } 
} 

public class CustomItemViewModel : ViewModelBase<CustomItem> 
{ 
    public string Title 
    { 
     // implementation excluded for brevity 
    } 

    public string Description 
    { 
     // implementation excluded for brevity 
    } 
} 
+0

Tôi đã sử dụng mô hình Generics như minh họa ở đây, và tôi có thể nói, tôi đã không thực sự có bất kỳ vấn đề nào với việc có một hệ thống phân cấp thừa kế cho ViewModels. –

+3

Nó chắc chắn sẽ làm việc mà không có vấn đề trong nhiều trường hợp. Tuy nhiên theo quan điểm của tôi, tôi thấy các lớp ViewModel được kết hợp chặt chẽ với Views. Thừa kế giữa các lớp ViewModel sẽ có ý nghĩa nếu các Chế độ xem được liên kết của chúng có chung một số giao diện người dùng chung. –

+0

Tôi đang đối mặt với cùng một kịch bản mà Richard gặp phải, ngoại trừ câu hỏi của tôi là về quan điểm. Tôi có một lớp trừu tượng với 10 trường, và các lớp con khác nhau của nó thêm vào nhiều trường khác (mỗi trường bổ sung thêm trường), tôi nên tạo các khung nhìn khác nhau như thế nào? Tôi không muốn redeclare các lĩnh vực cơ sở trong mỗi người trong số họ (tôi vẫn không chắc chắn về ViewModel chính nó, sẽ đánh giá cao sự giúp đỡ nào về nó quá). – Shimmy

3

Tôi muốn được quan tâm để xem nếu có một câu trả lời tốt hơn cho điều này, nhưng khi tôi đã có cùng một vấn đề tôi đã luôn luôn kèm theo một diễn viên rõ ràng của đối tượng như một tài sản cá nhân như sau:

class CustomObjectViewModel : ViewModelBase 
{ 
    protected readonly CustomObject CustomObject; 

    public CustomObjectViewModel(CustomObject customObject) 
    { 
     CustomObject = customObject; 
    } 

    public string Title 
    { 
     // implementation excluded for brevity 
    } 
} 

class CustomItemViewModel : CustomObjectViewModel 
{ 
    protected CustomItem CustomItem { get { return (CustomItem)CustomObject; } } 

    public CustomItemViewModel(CustomItem customItem) 
     :base(customItem) 
    { 
    } 
} 

Nó hoạt động, và nó là tốt nhất tôi đã đưa ra, nhưng chưa bao giờ cảm thấy rất sạch sẽ với tôi.

+0

Tôi nghĩ rằng nó thực sự là một ý tưởng tốt ... Bằng cách này bạn không sao chép đối tượng mô hình trong ViewModels thừa hưởng –

5

Liên quan đến những nhận xét trên của Enrico. ViewModels không nên được kết hợp chặt chẽ với quan điểm, nó phải là cách khác xung quanh. Các khung nhìn nên được ghép đôi với ViewModels. Một ViewModel không nên biết về một khung nhìn, điều này cho phép bạn kiểm tra đơn vị một ViewModel dễ dàng.Tất cả các tương tác giữa các khung nhìn với ViewModel sẽ được thực hiện thông qua các thuộc tính trong ViewModel (thuộc tính ICommand cho các hành động và các thuộc tính khác cho databinding).

Điều duy nhất đúng là ViewModel được kết hợp chặt chẽ với Mô hình, vì vậy việc sử dụng các generics ở trên cho phép rất nhiều khả năng mở rộng. Đó là mô hình mà tôi muốn giới thiệu.

Bằng cách cung cấp lớp ViewModel về cơ bản chỉ cần hiển thị Thuộc tính, nó cho phép bạn vẽ vào bất kỳ loại khung trình bày nào và tận dụng tất cả mã bạn đã sử dụng trước đó. Nói cách khác, nếu được triển khai đúng cách, bạn có thể thả cụm ViewModels của mình vào ASP.NET MVC ứng dụng và buộc xem các thuộc tính và không có thay đổi mã.

Bài viết hay về các khái niệm cơ bản về MVVM là: this one. Tôi thực sự nghĩ MVVM là điều tốt nhất hiện có để phát triển giao diện người dùng. Rõ ràng chúng ta không thể sử dụng nó vì nó đòi hỏi phải xây dựng một ứng dụng từ đầu bằng cách sử dụng phương pháp MVVM, nhưng khi bạn đang xây dựng một ứng dụng mới không phải là một vấn đề.

Một trong những gripe tôi có với ICommand là nó là trong PresentationCore hội đó là cơ bản cho WPF. Nếu Microsoft muốn ghép nối lỏng lẻo nó phải ở trong một hội đồng khác hoàn toàn.

+2

Hãy để tôi làm rõ quan điểm của mình: với "kết hợp" Tôi không có nghĩa là lớp ViewModel nên có bất kỳ sự phụ thuộc nào trên Chế độ xem. Tuy nhiên nó nên phơi bày dữ liệu/hành vi có liên quan đến những gì được hiển thị bởi View cụ thể nó đang được sử dụng với –

+1

Về gripe của bạn: điều này đã thay đổi trong .NET4.5: nó bây giờ là một phần của System.dll http: // msdn .microsoft.com/en-us/library/system.windows.input.icommand.aspx – jan

4

Tôi nghĩ rằng vấn đề ở đây là phải có một ViewModel cho mỗi Chế độ xem chứ không phải một Chế độ xem cho mỗi mô hình.

Lý do cho điều này là khá rõ ràng, vì bạn chỉ có thể đặt một đối tượng là DataContext, đối tượng đó phải là ViewModel cho Chế độ xem đó.

Các vấn đề liên quan