I have a PersonEditViewModel
which needs two other objects, the personId
and the PersonRepository
. PersonRepository
is obtained from a service locator:
private final int personId;
public PersonEditViewModel(int id) {
this.personId = id;
this.personRepository = ServiceLocator.get(PersonRepository.class);
}
But I would like to use dependency injection (DI, IoC) to obtain PersonRepository
, preferably via constructor:
public PersonEditViewModel(PersonRepository pr) {
this.personRepository = pr;
}
My problem is, how can I pass the personId
to the constructor in DI pattern? Do I have to make a setter for id - then DI changes the logic of the PersonEditViewModel
(the personId
field cannot be final)? Is it insufficiency of DI pattern that I cannot pass data objects to the constructor, or do I have to switch my mind and design my ViewModels other way, probably use other patterns to pass data objects to them?
Edit: Changed my question using personId
and PersonRepository
to be closer to common situations.
-
If you provide a bit more context you might get some answers. Are you using a particular framework and container? What does PersonService do?Ian Fairman– Ian Fairman06/18/2015 09:40:51Commented Jun 18, 2015 at 9:40
-
@Ian Fairman I've edited the question. It is a general question about DI pattern.xmedeko– xmedeko06/18/2015 11:36:13Commented Jun 18, 2015 at 11:36
2 Answers 2
In addition to what Ian has said in his answer, the following should give you a different perspective around this thing.
I try to answer following two questions about a dependency before I decide on the mechanism to pass the dependency object around.
- Am I going to be using the dependency?
- Who is responsible for instantiating the dependency?
The answer to first question in your context (I being PersonEditViewModel
) is yes. So somehow PersonEditViewModel
needs to get hold of appropriate Person
instance. Note that "appropriate" is key here but lets look into that in a bit.
Coming to second question, who is responsible for instantiating Person
class? Is it your IoC container? I don't think so. You are probably going to be loading appropriate instance of Person
class from a database or by calling a REST/WCF service. In any case, you should have another guy in the equation which is responsible for giving you the right Person
instance. If you are loading it from database then that guy can be a repository object. In which case, your next dependency is repository. Ask the same set of questions about repository again. Answer to first one is obviously yes. With regards to second one - can IoC container give an instance of (notice, there is no "appropriate" here) a repository. Yes, it can. So that becomes my dependency.
Coming to "Appropriate" - you are putting together this view model for a particular person instance. This particular person instance needs to be fetched from somewhere using right set of parameters like id, email address, name etc. You need a specialised implementation (repository for instance) to do that job. You cannot expect that IoC container would just hydrate this particular object for you somehow.
-
If I use Repository I have to pass
Person.Id
to thePersonEditViewModel
anyway, so it's not a solution to my problem.xmedeko– xmedeko06/18/2015 13:47:47Commented Jun 18, 2015 at 13:47 -
1True. I would not try to get DI container to do that for me. Sometimes, this id would need to passed down to hierarchy of dependencies and it starts becoming serious problem for DI pattern. In those cases, I have use abstractions that help with passing data objects around. This was specific to my use case but I can share details if you are interested.Suhas– Suhas06/18/2015 14:16:27Commented Jun 18, 2015 at 14:16
-
So it's a shortcoming of DI pattern. I think I can go with a
personId
setter and removefinal
keyword. Thank you.xmedeko– xmedeko06/18/2015 15:03:50Commented Jun 18, 2015 at 15:03
DI containers are generally used for plugging a limited number of long-lived objects together. Think of them as building the runtime structure of your program. Person looks like an entity to me - it will be loaded, used and discarded often. Also, you could potentially have an unlimited number of Person objects and it would not make much sense to use a container to configure them.
What you probably need is a PersonFactory and/or PersonRepository for managing the lifecycle of Person objects. These can be configured using a container. You could then wrap the factory/repository with another factory/repository that "injects" the Person into the ViewModel. The other services then use this factory/repository to do their work.
Hope that helps a bit.
-
Yes,
Person
is a short living object, entity or whatever. If I use Repository I have to pass Person.Id to thePersonEditViewModel
anyway, so it's not a solution.xmedeko– xmedeko06/18/2015 13:44:23Commented Jun 18, 2015 at 13:44 -
How do you know what Person to create in the first place? Where does that information come from?Ian Fairman– Ian Fairman06/18/2015 13:53:30Commented Jun 18, 2015 at 13:53
-
I think it's not important. It's about how to pass unmanaged data to the ViewModel. I have changed my question using id and repository to get away from "who creates
Person
".xmedeko– xmedeko06/18/2015 14:04:55Commented Jun 18, 2015 at 14:04 -
Then I'm not sure I can help. Without knowing what this code is trying to achieve from the user's perspective you're just left with an abstract problem. "how to pass unmanaged data to the ViewModel" has no meaning on its own.Ian Fairman– Ian Fairman06/18/2015 14:31:10Commented Jun 18, 2015 at 14:31
Explore related questions
See similar questions with these tags.