2

In a generic class I have to create a new object of the same type:

public abstract class ViewModel<TPrimaryModel>
{
    public void DoSomething()
    {
        ...
        ViewModel<TPrimaryModel> newViewModel = new TPrimaryModel(someArguments);
    }
}

Doing this isn't supported by C#. So I decided to introduce a CreateInstance-method:

public abstract class ViewModel<TPrimaryModel>
{
    public void DoSomething()
    {
        ...
        ViewModel<TPrimaryModel> newViewModel = CreateInstance(someArguments);
    }

    protected abstract ViewModel<TPrimaryModel> CreateInstance(Object someArguments);
}

public class UserViewModel : ViewModel<User>
{
    public UserViewModel(Object someArguments)
    {
        ...
    }

    protected override ViewModel<TPrimaryModel> CreateInstance(Object someArguments)
    {
        return new UserViewModel(someArguments);        
    }
}

The parameters which have to be passed (some Service-classes) are class variables. Unfortunately some ViewModels need some more services then others. Example: ViewModelA viewModelA = new ViewModelA(serviceA, 5, "ViewModelA"); ViewModelB viewModelB = new ViewModelB(serviceB, serviceA, 6, "ViewModelB");

I wonder what's the right way to go. Encapsulate the arguments for object creation? Factory pattern? Or should I avoid inheritance in that situation and stick to composition?

I could also always pass "all" services. Or provide a class which provides access to all services. But I guess those are bad ideas.

mosquito87
  • 4,270
  • 11
  • 46
  • 77
  • 1
    Where is `DoSomething` meant to get the arguments from? Surely that's problematic in itself... it would help if you'd explain a bit more about how the information flows. – Jon Skeet Nov 04 '16 at 08:39
  • Would it be possible to make the `DoSomething()` abstract, and then split its functionality into protected methods? – g t Nov 04 '16 at 08:40
  • @JonSkeet It just passes class variables as far as I can see. So this shouldn't be the problem. – mosquito87 Nov 04 '16 at 08:40
  • @gt I thought about that as well. But I have a lot of viewmodels. And `doSomething` really does some generic stuff. – mosquito87 Nov 04 '16 at 08:41
  • 2
    In the derived-class-constructor, store the arguments in private fields. And use them in the overriden `CreateInstance` method. Then you can remove the parameters of said method. – Maarten Nov 04 '16 at 08:43
  • Or just accept a `Func>` to start with... – Jon Skeet Nov 04 '16 at 09:03

1 Answers1

0

I don't know all too much about the rest of your architecture, but these would be my considerations:

If I already use DI: Most container support per service/type bootstrapping configuration. As long as you're not starting to do dynamic stuff during composition it should remain fairly comprehensive

Else: pass a Func<ViwModel<T>> factory method (as constructor parameter to your base class). It's probably the easiest and cleanest way to do what you want.

As you pointed out passing all services (would be an unmaintainable mess rather quickly) isn't a good idea. When it comes to the service locator pattern (quoting you "Or provide a class which provides access to all services"), this is a very opinionated discussion, with some very good insight over there: Is ServiceLocator an anti-pattern? If you ask me; there are more places where it's harming than the other way round. But hey, it's your software.

Community
  • 1
  • 1
pysco68
  • 1,136
  • 9
  • 15