开发者

How can I implement DI/IoC for a repeated and variable process without creating kernels on demand?

开发者 https://www.devze.com 2023-01-24 01:38 出处:网络
I know, this probably wins the award for longest and most confusing question title.Allow me to explain...

I know, this probably wins the award for longest and most confusing question title. Allow me to explain...

I am trying to refactor a long-running batch process which, to be blunt, is extremely ugly right now. Here are a few details on the hard specifications:

  • The process must run several times (i.e. in the tens of thousands);

  • Each instance of the process runs on a different "asset", each with its own unique settings;

  • A single process consists of several sub-processes, and each sub-process requires a different slice of the asset's settings in order to do its job. The groups are not mutually exclusive (i.e. some settings are required by multiple sub-processes).

  • The entire batch takes a very long time to complete; thus, a single process is quite time-sensitive and performance is actually of far greater concern than design purity.

What happens now, essentially, is that for a given asset/process instance, a "Controller" object reads all of the settings for that asset from the database, stuffs them all into a strongly-typed settings class, and starts each sub-process individually, feeding it whichever settings it needs.

The problems with this are manifold:

  • There are over 100 separate settings, which makes the settings class a ball of mud;
  • The controller has way too much responsibility and the potential for bugs is significant;
  • Some of the sub-processes are taking upwards of 10 constructor arguments.

So I want to move to a design based on dependency injection, by loosely grouping settings into different services and allowing sub-processes to subscribe to whichever services they need via constructor injection. This way I should be able to virtually eliminate the bloated controller and settings classes. I want to be able to write individual components like so:

public class SubProcess : IProcess
{
    public SubProcess(IFooSettings fooSettings, IBarSettings barSettings, ...)
    {
        // ...
    }
}

The problem, of course, is that the "settings" are specific to a given asset, so it's not as simple as just registering IFooSettings in the IoC. The injector somehow has to be aware of which IFooSettings it's supposed to use/create.

This seems to leave me with two equally unattractive options:

  • Write every single method of IFooSettings to take an asset ID, and pass around the asset ID to every single sub-process. This actually increa开发者_开发技巧ses coupling, because right now the sub-processes don't need to know anything about the asset itself.

  • Create a new IoC container for each full process instance, passing the asset ID into the constructor of the container itself so it knows which asset to grab settings for. This feels like a major abuse of IoC containers, though, and I'm very worried about performance - I don't want to go and implement this and find out that it turned a 2-hour process into a 10-hour process.

Are there any other ways to achieve the design I'm hoping for? Some design pattern I'm not aware of? Some clever trick I can use to make the container inject the specific settings I need into each component, based on some kind of contextual information, without having to instantiate 50,000 containers?

Or, alternatively, is it actually OK to be instantiating this many containers over an extended period of time? Has anybody done it with positive results?


MAJOR EDIT

SettingsFactory: generates various Settings objects from the database on request.

SubProcessFactory: generates subprocesses on request from the controller.

Controller: iterates over assets, using the SettingsFactory and SubProcessFactory to create and launch the needed subprocesses.

Is this different than what you're doing? Not really from a certain angle, but very much from another. Separating these responsibilities into separate classes is important, as you've acknowledged. A DI container could be used to improve the flexibility of both Factory pieces. The implementation details are, in some ways, less critical than improving the design, because once the design is improved, implementation can vary more readily.

0

精彩评论

暂无评论...
验证码 换一张
取 消