-1

I know there is plenty of questions about this, but there is a lot of seemingly conflicting information.

My assumption: The viewmodel is an abstraction of the view, an interface to the business logic, if you will. Therefor if the viewmodel is an abstraction of the view, it makes sense for it not to depend on its implementation. So the viewmodel is unaware of any view. I assume the Viewmodel is kind of a proxy for the view, exposing controls that can be manipulated by whoever owns the viewmodel. So what class owns/uses the viewmodel? The model is of course unaware of any viewmodel, as it only holds the state of the application. So I like to introduce a controller to take care of concrete business logic. Which in my opinions allows for much more loose coupling.

This is how I imagine the dependency relationship:

sketch

So to be more concrete. How can I imagine the dependency relation between the different components? And how much sense does the introduction of a controller (for processing logic) make and most of all how correct am I in my assumptions make?

Esguio
  • 3
  • 1

2 Answers2

1

Your assumption about the ViewModel is incorrect, because it actually works the other way around. The ViewModel acts in part as a View-specific proxy of the Model (and in part as a model for the non-business properties of the View, like current selection). Typically, the ViewModel will contain a class for every View in the application.

The model is of course unaware of any viewmodel, as it only holds the state of the application.

It is correct that the Model is unaware of the ViewModel, but that is not because the Model is just a data repository.

The Model is responsible for all the business logic (that what would remain the same if you put a different kind of UI on the application), but it doesn't know when the application needs which information. The Model can offer notifications that the various ViewModel classes can subscribe to as needed.

The typical flow is that either a human user takes an action in a View or an external event occurs, either of which triggers the Model to make a change to itself. Then the Model notifies the interested listeners of the change, which can trigger an update of a View.
Additionally, a user action can also trigger an update of the View, where that update retrieves the latest status from the Model (by way of the ViewModel).

  • Thanks for the explanation. Could you clarify what the relationship would be? Because at the end of the day, either the model or the viewmodel will have to depend on the other. How would you approach this? And what is the difference between the controller (in MVC) and the model since both handle business logic. – Esguio Mar 17 '20 at 09:12
  • Also, in your opinion would a further separation of the model into controller (as in MVC) and the model (as in data model) make any sense? – Esguio Mar 17 '20 at 09:15
  • @Esguio, the ViewModel knows about the Model (knows class names and methods). Depending on the implementation language, the Model can send notifications back through an event interface or an implementation of the Observer pattern. In this way, you can say that the ViewModel depends on the Model. – Bart van Ingen Schenau Mar 17 '20 at 09:51
  • @Esguio, the Controller from MVC should not contain/handle business logic, but only receive user actions in the form of keypresses, mouse clicks or web requests. It should be possible to take the Model from an MVC application and use that in an MVVM application without loss of functionality. – Bart van Ingen Schenau Mar 17 '20 at 09:55
  • @Esguio, it is definitely a good idea to structure the Model part further, beyond what the MVVM/MVC patterns describe. How to name those parts you divide the Model into is opinion based, but in my opinion the term controller might be confusing. I would then prefer calling it a Service layer. – Bart van Ingen Schenau Mar 17 '20 at 09:59
1

Generally:

  • The Model does not know about View or ViewModel.
  • The View does not know about the Model, but knows about the ViewModel.
  • The ViewModel does not know about the View, but knows about the Model.

How much each of these things knows about the other and how they are created, managed, and connected all depends on the layer you use to implement the MVVM abstraction itself.

Questions like:

  • Who creates Views?
  • Who creates ViewModels?
  • Who initializes the Model?

will all depend on what MVVM framework you're using, or if you're rolling your own implementation.

For instance, in .NET + WPF, the View knows about the ViewModel by binding to properties/methods/commands by name and then setting the DataContext property of the View to an instance of the ViewModel. How you create that ViewModel is left up to you though. You might use an inversion-of-control (IOC) container to provide the instance, or you might create it yourself.

Regardless of whether or not you use a framework, there will always be some amount of code "above" the MVVM abstraction which will orchestrate data-flow and initialization.

Even if you do use a framework, you will eventually run into cases where you will need to add some additional code "above" to help "open a new Window/Dialog" or do some other application-specific thing. As long as the majority of the important stuff lives within the MVVM abstraction (so that your Models and ViewModels are fully testable without needing to create Views), and as long as you don't violate the relationships between the Model, View, and ViewModel, you'll be in a good spot. Every now and then though, it is good to review any code "above" the MVVM abstraction, and see if you can move any of it "into" the abstraction to maximize the benefits.

As a side note, you should definitely consider whether or not you need the MVVM abstraction in the first place. The primary benefits of MVVM are the ability to unit test Views and the ability to re-use ViewModels with different Views and even across entirely different projects/platforms. If you don't have these needs, you'll likely be better off simply keeping your View and Model layers separated (the Model should never know about the View, but the View can talk directly to the Model via methods/properties and can subscribe to updates). While this doesn't grant you a re-usable or testable abstraction over your Views, it still keeps your Model re-usable and testable, which is arguably the most important pattern in UI application development.

Edit:

To clarify on what I mean when I say "above" vs "inside" the MVVM abstraction. If code is "inside" the MVVM abstraction, it is correctly following all of the rules and guidelines of MVVM. If code is "above" the MVVM abstraction, it is either coordinating the abstraction in some way (ie: a Messenger class that allows ViewModels to communicate with each other) or it outright breaks/ignores the abstraction in some way.

To give an example of some WPF code that you might write that would be considered "above":

public class App : Application
{
    public static void TryCloseWindowForVM(IViewModel viewModel)
    {
        IView view = SomeMVVMFramework.LocateView(viewModel);

        if (view is Window window)
            window.Close();
    }
}

Here, we provide a method on the App class that allows ViewModels to call something like App.TryCloseWindowForVM(this) in order to attempt to close the Window that the View this ViewModel is associated with. This will certainly throw all sorts of errors if the View and ViewModel are not associated yet, or if the View for this ViewModel is not a Window, or maybe even if there are multiple Views for this ViewModel (which can be the case in some frameworks).

This code could also be seen as rather dirty or harmful depending on what kind of rules you are willing to break. In my own experience, you'll always end up with some of this code in order to get certain things done (though sometimes there are better ways and it's always good to research first).

  • Could you calirify what you mean when you write "above". Would you consider Helper classes or for example the use of a specific design pattern "above"? – Esguio Mar 19 '20 at 14:25
  • When I say "above", I'm mainly referring to code that will coordinate the MVVM abstraction itself. If you use a framework, it's likely you will have very little of this code, maybe just bit of configuration/customization of the framework behavior. For instance, any "Locator" type classes that determine how the framework decides to automatically connect Views with ViewModels. Really though, you COULD have any code you want "above", which just means that code doesn't follow the MVVM rules, or even breaks them, which might be a good/bad idea depending on how well that code fits within MVVM. –  Mar 19 '20 at 15:43
  • Ultimately, when using an application-wide abstraction like MVVM, it's better to minimize this code, as it can highly undermine the benefits you get by using MVVM in the first place. –  Mar 19 '20 at 15:44
  • See my edit for an example of code that is "above" –  Mar 19 '20 at 16:00