How can achieve this class structure with the right visibility modifiers?

Viewed 124

I'm working on a project with several people and wanted to enforce some structure to the code without having to write it somewhere and depend on each person to remember, and apply the concept.

I'm working on a framework that handles files and data, my current structure is something like this (the first row is the namespace, second the class name).

Current Structure:

Current Structure

My intention is to make FileManager and DataManager only available to the EngineWorker so no one outside can use them directly enforcing to use them through methods in EngineWorker. I found only 2 ways of doing so, removing the static keyword and make an instance inside EngineWorker private, or join all classes into the same Assembly in all cases and change the access from public to internal.

I was hoping there is another way, something that could let me keep the classes as static and the Assemblies as they are. Maybe because they both have the same "parent" namespace Product.FrameWork?

1 Answers

I think this is a really good question, I came across the same situation a while ago and could never find a perfect solution for it.

One solution that I could think of was to put EngineWorker, DataManager and FileManager in the same project (let's call it IO.Project) and make the last two classes internal to ensure the outside world is accessing them through EngineWorker:

IO.Project

public class EngineWorker
{
    private DataManager _dataManager;
    private FileManager _fileManager;

    /* 
     * The limitation of this approach is that the outside world does not know about
     * the internal classes, so you cannot use constructor injection:
     * 
     * public EngineWorker(DataManager dataManager, FileManager fileManager)
     * {
     *    _dataManager = dataManager;
     *    _filerManager = FileManager;
     * }
     */

     // you can pass the internal dependencies into the constructor
     public EngineWorker(DbContext dbContext, FileManagerDepencency fileManagerDependency)
     {
        _dataManager = new DataManager(dbContext);
        _fileManager = new FileManager(fileManagerDependency);
     }

     // or you can use a Factory to instantiate EngineWorker
}

internal class DataManager
{
    private _dbContext;

    internal DataManager(DbContext dbContext)
    {
        _dbContext = dbContext; 
    }

    internal void DoWork()
    {
        // do something
    }
}

internal class FileManager
{
    private _fileManagerDependency; // <-- if this class has any dependency?

    internal FileManager(FileManagerDependency fileManagerDependency)
    {
        _fileManagerDependency = fileManagerDependency; 
    }

    internal void DoWork()
    {
        // do something
    }
}

The limitation of this approach is that the internal classes cannot be injected, because the outside world does not know about them... instead you can use a Factory/Provider to instantiate the EngineWorker... or you could pass the dependencies (e.g. DbContext) to the constructor and let the EngineWorker constructor instantiate its internal members.


The other solution would be to make all three classes public (this way you can use constructor injection). But we still want to prevent the outside world to use DataManager and FileManager directly... in order to achieve this we make their methods (DoWork() in the example above) intenal.

Related