Question

I'm currently using an IoC container, unity, for my program.

I have multiple chained factories. One calling the next to create an object it needs for populating a property. All the factories use the same raw data object in order to build their respective objects. The raw data object describes how to create all the various objects. Currently each factory has a Create method that takes in a couple parameters to state what location the object represents.

My problem is how/where do I pass in the raw data object to each factory in order for them to do their jobs?

Injecting the object into the Create() methods seems to be more procedural than object oriented. However if I inject the object into each factory's constructor then how would I resolve each factory correctly. Not to mention that these factories need to be able to work on different raw data objects. Maybe there is a better architecture over all?

Below represents the type of structure I have, minus passing the raw object anywhere.

class PhysicalObjectFactory
{
    private readonly StructureAFactory _structureAFactory;
    private readonly Parser _parser;

    public PhysicalObjectFactory(StructureAFactory structureAFactory, Parser _parser)
    {
        _structureAFactory = structureAFactory;
        this._parser = _parser;
    }

    public PhysicalObject CreatePhysicalObject()
    {
        RawDataObject rawDataObject = _parser.GetFromFile("foo.txt");
        // do stuff
        PhysicalObject physicalObject = new PhysicalObject();
        physicalObject.StructureA = _structureAFactory.Create(num1, num2);
        // do more stuff
        return physicalObject;
    }
}

class StructureAFactory
{
    private readonly StructureBFactory _structureBFactory;

    public StructureAFactory(StructureBFactory structureBFactory)
    {
        _structureBFactory = structureBFactory;
    }

    public StructureA Create(int a, int b)
    {
        // do stuff
        StructureA structureA = new StructureA();
        structureA.StructureB = _structureBFactory.Create(num76, num33);
        // do more stuff
        return structureA;
    }
}

class StructureBFactory
{
    public StructureBFactory(){}

    public StructureB Create(int a, int b)
    {
        StructureB structureB = new StructureB();
        // do stuff
        return structureB;
    }
}
Was it helpful?

Solution

My problem is how/where do I pass in the raw data object to each factory in order for them to do their jobs?

In general you should pass in runtime data through methods and compile-time/design-time/configuration data through constructor injection.

Your services are composed at a different moment in time as when they are used. Those services can live for a long time and this means they can be used many times with different runtime values. If you make this distinction between runtime data and data that doesn't change throughout the lifetime of the service, your options become much clearer.

So the question is whether this raw data you're passing in is changing on each call or if its fixed. Perhaps it is partially fixed. In that case you should separate the the data; only pass the runtime data on through the Create methods. It seems obvious that since the factories are chained, the data they need to create that part of the object is passed on to them through their Create method.

Sometimes however, you've got some data that's in between. It is data that will change during the lifetime of the application, but do don't want to pass it on through method calls, because it's not up to the caller to determine what those values are. This is contextual information. A clear example of this is information about the logged in user that is executing the request. You don't want the caller (for instance your presentation layer) to pass that information on, since this is extra work, and a potential security risk if the presentation layer forgets to pass this information on, or accidentally passes on some invalid value.

In that case the most common solution is to inject a service that provides consumers with this information. In the case of the user information you would inject an IUserContext service that contains a UserName or UserId property, perhaps a IsInRole(string) method or something similar. The trick here is that not the user information is injected into a consumer, but a service that allows access to this information. In other words, the retrieval of the user information is deferred. This allows the composed object graph to stay independent of those contextual information. This makes it easier to compose and validate object graph.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top