5

I'm struggling with the design in a WPF MVVM application. In a few courses I've taken, they say that having a lot of parameters in a constructor is a code smell, but they never address how to deal with it.

In a recent project of mine we used dependency injection to provide services that follow a data adapter pattern. Each of these classes are focused on a type, such as vendor, employee, detail, quote, request for quote, etc.

In this application the high level view models don't do much, but they host several view models, such as: details, file attachments, notes, vendor selection, and vendor requirements. The constructor for the unprocessed details view model takes almost every service in its constructor, but only uses those parameters to construct its child view models.

It doesn't make sense that the main view model would know about a detail view model, because the main view model is only responsible for top level navigation. So what approach can be used to compose the high level view models without a lot of constructor parameters, or is it not a bad practice in this case because the high level view models are responsible for composing the low level view models?

  • 3
    @gnat: not even close – Doc Brown Aug 17 '18 at 13:51
2

Our team had the same problem with view models in the ASP.NET MVC framework. Composing the view hierarchy started becoming complex, and as the user interface evolved we had to make changes higher and higher up in the view model structure, and then propagate those changes further and further down by passing constructor arguments.

We came to realize that a view model representing an entire web page really needed a lot of information from multiple sources. Even then we were able to reuse view models in multiple contexts, but configured just a little differently.

I came to the realization that these "top level" view models really represented a use case in the application, and had different initialization needs than view models that represented parts of a web page — individual components.

We introduced view model factory objects that specialized in initializing the complex view models. View models that represented a single component on screen had fewer dependencies, and we were able to continue initializing them through constructor parameters.

There was no clear line that got crossed where we said "we need a view model factory!" It became a gut feeling. When initializing a view model becomes complex, we moved the initialization logic into a factory method, but initializing view models remains the responsibility of each view model's constructors until we reach that point.

  • Just want to be perfectly clear. You made one factory for all complex view models, not multiple factories. Did you use a DI like ninject within that factory? – Adam Aug 17 '18 at 13:29
  • 1
    We started with a single factory, but we started creating one factory per controller class in our web application. We aren't using a DI framework, but we are still using dependency injection by passing in repository objects. Whether you use one or multiple factories really comes down to a gut feeling again. If it is too big, split it up. The Single Responsibility Principal is a good guide in this case. – Greg Burghardt Aug 17 '18 at 13:32
  • What made it necessary to begin using factories? The complexity of the object graph? Would an IoC container have been a suitable alternative? – Robert Harvey Aug 17 '18 at 14:10
  • @RobertHarvey: It was the complexity of the object graph. Our application doesn't use an IoC container at the moment. We started this application with an inexperienced team, and IoC was just too big of a mountain to climb at that time. – Greg Burghardt Aug 17 '18 at 14:27
  • That's interesting. Maybe it's because I've never worked in an enterprise Java shop, but I've never felt the need to use an IoC container in any of my own projects. DI containers were hopelessly opaque to me until I realized they were (in the typical case) just an interface/implementation mapper. Then they felt ridiculously simple (in principle, if not in actual execution). My current work project uses an IoC container to register new modules, and I have to admit it is quite convenient and fun to hand-wave the new keyword. We use DryIoc; it's faster than most of the others. – Robert Harvey Aug 17 '18 at 14:32

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.