I'm working on client-server application. Client architecture (class hierarchy) looks like this:
System
(name is of course different, more descriptive) - represents whole systemModule A
- a class instance representing one module. One module = group of similar data and operationsUser Module
- another moduleUsers
- class instance which represents collection of users, allows adding, removing, reading, etc.Groups
- represents user groups
- etc.
Architecture above represents the system, data, operations. Handles client requests and server responses. Caches queries if required. But it does NOT handle GUI, for that I use separated code. The most of the gui uses view for displaying data which is based on simple logic: one view (class) type represents a view of one (single) item type. For example UserView
displays data about user (from User
instance).
Often the item represents a collection of items. For example there might be item like UserEvent
which contains some name (of the event), date and list of users. However, the list of users is implemented as list of IDs (UserId
), nothing more. So now UserEventView
takes this list and wants to create instances of UserView
in order to display more detailed information about users (for example as list of name). So now the UserEventView
needs to access Users
to translate UserId
to User
in order to provide UserView
correct data. So, what's the best way for the UserEventView
to access Users
?
I can see multiple ways how to solve it, but none seems to be ideal:
Singleton
- the most simple and easiest way. Either ofSystem
(even thoughUserEvenView
doesn't care about it) or for every single module.Users
instance is given toUserEventView
by it's parent, which is provided by it's parent, which is provided by it's parent, ...- There is
UsersProvider
component attached to theUserView
which searches for GUI root where it searches for a component which providesSystem
instance and obtainsUsers
from it.
Notes:
- If you want to suggest some exception in design for users, then imagine I'm working with cars, shoes, anything.
- The app is written in C#/C++.
1 Answer 1
Create a repository to wrap whatever stores you users with appropriate methods
IUserRepository
{
GetUserById(string id);
}
Instanciate a concrete instance of this at the root of your app
class System
{
public void Main(string[] args)
{
var repo = new MyUserRepo();
....
}
}
and pass it into object that need it via construction parameters. ie.
class UserViewModel
{
public UserViewModel(IUserRepository repo)
}
Now your various ViewModels and/or Controllers etc can get Users without being tightly coupled to the rest of the App.
Note: Although this pattern is usually used to wrap a database, theres no reason why you cant wrap a List or Dictionary of in memory Users instead
-
Do I understand it correctly that this is more-or-less same solution as my 2nd (but instead of passing
Users
,IUserRepository
is being passed)? Meaning that ifUserViewModel
is deep in hierarchy, theIUserRepository
instance must be passed through all parents?Tom– Tom2018年06月08日 11:28:34 +00:00Commented Jun 8, 2018 at 11:28 -
yup, although if you have parents outside of your general framework its a bit of a code smellEwan– Ewan2018年06月08日 12:40:27 +00:00Commented Jun 8, 2018 at 12:40
-
I'm not sure how to understand that last comment, but it's not problem to modify the code to pass these things around, but some gui screens are huge and so their constructor would need like 20
XYZRepository
s for different part of gui and that's what I'm trying avoid. (Also, I cannot pass it through constructor, because the repository can change during the application execution.)Tom– Tom2018年06月08日 13:47:53 +00:00Commented Jun 8, 2018 at 13:47 -
sounds like you have more problems than just the example outlined in your question. Injection is great but its not magicEwan– Ewan2018年06月08日 14:00:19 +00:00Commented Jun 8, 2018 at 14:00
-
I'm not sure what do you mean. (The gui is simply complex and my point was that different elements need lots of different repositories in total - and constructor of main screen would need to take a lots of arguments.) Anyway, do I understand correctly, that what are you suggesting is generally dependency injection? (Not only through constructor, but - for example - during deserialization phase (loading gui)?)Tom– Tom2018年06月09日 08:48:04 +00:00Commented Jun 9, 2018 at 8:48
Explore related questions
See similar questions with these tags.
UserEventView
andUserEvent
and (currently) nothing more. I don't know (and don't care) whether this particularUserEventView
wants to display user names or not (and just count, for example). So non-gui code preparing the data a) would need to know whether it's going to be passed to gui which needs the user names or not, or b) always fetch user names even if they're not used.