I return to this question every couple of years, so now i decided to solve it once and for all, by asking here.
So, the sequence:
- I'm writing a simple application that parses Json file (configuration to 3rd party app, further named as config) and allows user to do some editing with it. I've picked a platform, made some basic UI, binded some buttons to NewFileCommand, OpenFileCommand, SaveFileCommand, etc.
- Now I need to store somewhere the opened (and deserialized into a class) config, so I made a new StorageService class. It has some methods like OpenFile(), ReloadFile(), SaveFile(), etc. They are called from the ViewModel, StorageService opens file, read the config and store it as a field. When needed, it saves it to a file - so far so good.
- At this moment, I want to add some manipulations with the config itself. I really dont want to put it in the StorageService. Some methods like GetConfigPropertyByNameAndDoSomeMagicWithIt() are definitely should be placed to another service.
- So, i made another service, OperationsService. Now i want it it have an access to the config, stored in StorageService and add methods GetConfigPropertyByNameAndDoSomeMagicWithIt(). I dont want to expose the StorageService.config into the public API - because i already have all necessary accessors. For everyone else, except of OperationsService. Which i pretty much want to make the one, who can access StorageService.config. Looking like a good use case for old good C++ concept of the "friend" class, where OperationsService can be declared as a friend of StorageService and access its internals.
- I'm recalling that I've faced similar issue earlier, so I googled for "C# friendly class", opened the first link in a hope to find a modern solution - and realized that I've a deja vu feeling.
So, what is a flow in my current approach? How to solve it in "proper modern OOP architecture" manner?
Make OperationsService an internal class of StorageService? That would mean that all the code would be stored in the same file (pretty much violation of SOLID).
Make OperationsService an internal class of StorageService and make it partial and move to another file? Seems kinda creepy.
In general, I don't even want OperationsService to be exposed (not even to register it in IoC container) for the rest of the app - just to do the heavy lifting. OperationsService would be not that large, so I don't want to make a third (some kind of a wrapper service) as well.
In terms of objects I can rephrase the problem as "object A has a private field, which should be accessible only for object B. Object's A responsibility is IO, Object's B responsibility is some logic, so they cant be merged".
To sum up, we have:
- config, which is POCO and contains deserialized data from Json.
- StorageService, which contains OpenFile(), SaveFile(). Also, it contains current instance of the config.
- theoretical OperationsService, which contains some logic in GetConfigPropertyByNameAndDoSomeMagicWithIt(). In order to run that logic, it has to have an access to the config as well. The question is how to relate OperationsService and StorageService.