简体   繁体   中英

Should I reuse view models in different views?

I noticed that I have views that need the same information like others. But sometimes you need 5 properties of the view model and sometimes only 2.

Do you share such view model over many views or do you create a separate view model for each view or maybe do you prefere an inheritance or composition strategy?

For me there are some disadvantages for sharing view models:

  1. Principle of Least Surprise: It is strange to fill only 2 properties of 5 of a view model and get null reference exception, because you don't want to query additional data of the database. When the view model has 5 properties I expect that all are filled. The exceptions prove the rule.
  2. Separation of Concerns/Single Responsibility Principle: The view model cluttered up on complex sites, because you have to suit different needs for each view. If logic is involved its getting more complex, too.

What do you think? How do you handle such circumstances?

People tend to have different philosophies of ViewModels based on their perspective of their use. ViewModels are the glue between a view and a model and people will typically base their answer on which of the two ends they like to hold more rigid.

  • If you like your model/data objects to be more rigid, then you'll tend to tie the ViewModel closer to the model/data—ie you'll have a single ViewModel that is used in multiple views and let the ViewModel determine which properties to retrieve based on how you want to handle data loading (and defer things like images or other long-load properties, etc.).
  • If you like your Views to be more rigid, then you'll tie the ViewModel closer to the View—ie have a separate ViewModel for each view and let the model/data objects handle things like syncronization as you move from view to view.

Personally, I prefer the first as my data tends to be more rigid because it's less likely to change than the views are (in my projects—I don't think that's a universal property of data and views). Since change notifications are a natural feature of ViewModels, I don't have to make my model objects communicate changes if a user happens to have two views up that show the same/similar data.

In the project I am working on, each view has its own ViewModel, however we also have CollectionViewModels, which are shared/referenced by multiple view models.

Think - a list of Suppliers, that needs to be displayed in multiple screens in your application - and is bound to a variety of controls - a list box, grid view, whatever you need. Having just one ViewModel makes for simpler update/refresh logic of the list of Suppliers.

TLDR: I would only reuse view models, if all usage cases use the ViewModel in the same way. Ie they all use the same properties etc.

I would have a seperate ViewModel for each view. Unused properties make the code less readable (Why is that property present if it isn't being used?). If you have the same functionality for a fixed set of properties over several views I could see using a base class which contains those properties.

Definitely one ViewModel per View, imho.

As your application grows in complexity shared ViewModels will tend to grow, and it doesn't feel great to pass an object with 50 properties to a View when all it needs is one property.

Also, sometimes you may want to add extra properties in your ViewModel that are absolutely specific to your View and that you don't need in other Views. Say you have a CSS class that depends on properties from the ViewModel. Instead of writing if else statements in your View, you create a property in the ViewModel that returns the correct css class based on whatever business rules you have. This way you make the View as slim as possible and with a dedicated ViewModel you are not sharing a CSS class name with Views that don't really care about it.

I usually share ViewModels. As I understand it, the advantages of using view models are (a) security, in that properties that should be hidden are and (b) separation of concerns between business and presentation layers. (b) is accomplished just the same while sharing view models.

As for (a), I'm rarely in a situation where exposing a property is a security risk in one place but not in another. If a property needs to be hidden, it probably needs to be hidden everywhere. Of course, YMMV, but this seems like a fairly subjective question.

I use Entity Framework with Code First so my domain classes need to remain pretty rigid as they will be mapped to a sql database.

Some views use just one directly mapped entity and that's just great so I use the same domain layer entity. If that entity requires more information (two password fields for example) I will use composition. 'Composition should be favoured over inheritance', so if you can use composition do so, usually as it's just additional properties, composition can be used.

If there is a screen that uses only two properties of that entity, or I want to hide properties due to security concerns, I create a new view model and only retrieve the necessary data. I will reuse view models but only if the same properties are required in that other view.

I would share a VM between multiple view only if all properties variables and methods are used by all the views otherwise I would use inheritance and abstract base view model and if this does not solve. Do 1 to 1

TLDR: Yes (if you really want to use it and know how to use it wisely).

I can think of three responsibilities wanted from view model layer:

  1. coupling view layer & model layer together
  2. offering interface for unit testing
  3. separating logic into small pieces when a single page is complex

The first responsibility actually conflicts with the second. Because once a view model knows (couples with) the view class to initiate, it cannot be unit tested. Knowing the model (and its provider) class to initiate doesn't cause this problem. However if the provider is a singleton, the unit test become less "unit".

When comes to the third responsibility, there is a kind of logic that I call them routing. For example, after clicking on a button, the user should see the next page. Which layer is this kind logic supposed to lie in? View? Model? Definitely NOT! It has no where to go but view model. Once a view model knows the class of the view model of the next page to initiate, it makes a giant view model tree to be dealt with. Because this happen recursively – the next page also knows the next next page. No matter on which node in this view model tree, once a change happens, it reflects on the parent nodes. How to deal with these reflections? Subclassing? Remember, in the tree, a node can have hundreds of direct / indirect child nodes.

Conclusion – view model is good at the third responsibility only if it drops the first. The only one it is really good at is the second responsibility. However, I see nobody mentioning it under this question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM