I really appreciate all the other answers. They will help me solve this problem. I will most likely be accepting the Remo answer, as it corresponds to the current problem that I am really facing.
For my understanding, I would also like to receive feedback on this broader answer that I came up with.
I was not sure that Injection Dependency directly supports the mechanisms I spoke of through a constructor, property, or injection method. This is what I consider to be a “pure” DI at the moment, although I am ready for it to swing.
I thought injection dependencies meant a relatively static graph of objects. It can be loaded from a configuration file or generated using a procedure, but it cannot directly place an unrecognized execution state, for example, a user repeatedly requests new instances.
However, after thinking through some of these alternatives, I begin to think that there is a workaround that supports purity, and that maybe the purity that I described is not as important as I thought. Some of the less “clean” options still work with most containers in a mostly clean way, and it seems easy enough to add container support to clean them to the end.
Here are the workarounds that I have reviewed so far (some of them have already been mentioned).
Link to the container in custom factories, then wash your hands:
Your components can be implemented as you wish. You can use any container you need (if it supports temporary instances). You just need to live with the fact that you will enter the factories in your code and that these plants will be solved directly from the container. Who needs cleanliness when you can pragmatically?
Code example:
public class ComponentFactory // Might inherit from an interface... { private readonly IContainer container; public ComponentFactory(IContainer container) { this.container = container; } public IComponent Create(IOtherComponent otherComponent) { return container.Get<IComponent>(otherComponent); } }
Use the factory extension for the container:
Your components can be implemented as you wish. But your container must directly support the injection of factories into your code and automatically execute these plants so that they do not have any specific knowledge about the container.
Code example:
Use a pool of container-specific objects:
Make sure your components are stateless and allow you to combine them. The container will take care of selecting or combining objects for you. This is a more or less managed factory with a fancy implementation that you need to both distribute and free.
Pseudocode (I have not used a pool of conatiner-based objects before):
public class SomeUI { private readonly IComponentPool componentPool; public OtherComponent(IComponentPool componentPool) { this.componentPool = componentPool; } public void DoSomethingWhenButtonPushed() { var component = componentPool.Get(); component.DoSomething(); componentPool.Release(component); } }
The advantage of this pseudo code is that you did not need to define an interface for your factory. The downside is that you had to depend on the interface of the pool, so your container has your antennae on you. Also, I was not able to pass anything to the Get method. This probably makes sense, since objects should support instance reuse.
If real pools do not work like that, they may look identical to the factory extension container described above, only they always require the Release method along with the Create method.
Use the Flyweight template:
( Flyweight Pattern - Not sure if I defined the pattern correctly, or if I just have a weird use for it)
Introduce a stateless component that acts like a behavior for your objects or a "heavy weight" component. Maintain separate “instances” of the component by using fly state objects that you pass to the behavior component, or force them to wrap the behavior component.
This will significantly affect the architecture of your components. Your implementations must be inactive, and your state object must be designed so that it works for all possible component implementations. But it fully supports the “clean” injection model (only injection into constructors, properties, methods).
This will not work well for user interfaces. Class views usually need to be created directly, and we don’t want our flies to be a user interface class ...
public class ComponentState {
Use child containers for each new instance that the user requests:
A container works best when creating a graph of objects from a single root. Instead of trying to fight it, work with it. When the user clicks the button to create a new instance of your algorithm, create a new child container for these objects and call the global configuration code, however this must be done. Then attach the child container to the parent container.
This means that spawning code needs to know about the container at some level. Maybe wrapping it in a factory is the best way.
public class SubComponentFactory // Might inherit from an interface... { private readonly IContainer container; public ComponentFactory(IContainer container) { this.container = container; } public IComponent Create(IOtherComponent otherComponent) {
The view looks like we started. But we have a new graph of objects, so I'm not sure I can call it to use the Service Locator template. The problem with this approach is most closely related to the container. Not only is the container directly referenced, but the factory relies on the implementation detail of the container supporting child containers.