HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Best way to pass parameters to Factory class?

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
classpassfactorywayparametersbest

Problem

So I have a series of objects, which I will call Impl1, Impl2, and Impl3. They each implement an interface, called IImpl. I have a Factory class who's task is to retrieve the ImplX which is appropriate for a given circumstance, and pass it on to its callers. So the code in the factory looks like:

public IImpl GetInstance(params object[] args)
{
    if (args[0]=="Some Value")
         return new IImpl1();
    else if (args[0]=="Other Value")
         return new IImpl2(args[1]);
    else
         return new IImpl3(args[1]);
}


So depending on the arguments passed in, different instances are selected. All well and good and works ok. The problem now is, that I have a class which needs to call this factory method. It has no references to IImplX, which is good, but it winds up having to know exactly how to construct the input array to GetInstance, in order to ensure it receives the correct kind of instance. Code winds up looking like:

switch (_selectedInputEnum)
{
    case InputType.A:
        myIImplInst = Factory.GetInstance("Some Value");
    case InputType.B:
        myIImplInst = Factory.GetInstance("Other Value",this.CollectionB);
    case InputType.C:
        myIImplInst = Factory.GetInstance("Third Value",this.CollectionC);
}


This feels very redundant, and off somehow. What would be the best way to abstract the actual parameters of the factory? I feel like with the above switch statement, I am strongly coupled to the implemenations of IImplx, even if I don't have a direct reference.

Solution

How about some kind of intermediary blackboard that the client code constructs before calling the factory, and each concrete Impl can poll to construct itself?

// client code:

Blackboard blackboard = new Blackboard();
blackboard.pushCollectionB(collectionB);
blackboard.pushCollectionC(collectionC);
blackboard.pushFoo(foo); 

IImpl myInstance = Factory.GetInstance(b);

///////////////////////////

// in Factory.GetInstance():

return new Impl3(blackboard);

////////////////////////////

// in Impl3:

Impl3(Blackboard b) { process(b.getCollectionC()); }


I've hidden the switch statement in the client code, but you could move that into the blackboard as well.

What data each concrete Impl needs is now hidden from both the Factory and the client code. However if you need more data in your Blackboard for Impl(x+1) you will need to update every place in your code that creates a Blackboard.

Depending on application, over-constructing the Blackboard like this may be expensive for you. You could construct a cached version at startup, or you could make the Blackboard an interface and have your client code derive from it.

Code Snippets

// client code:

Blackboard blackboard = new Blackboard();
blackboard.pushCollectionB(collectionB);
blackboard.pushCollectionC(collectionC);
blackboard.pushFoo(foo); 

IImpl myInstance = Factory.GetInstance(b);

///////////////////////////

// in Factory.GetInstance():

return new Impl3(blackboard);

////////////////////////////

// in Impl3:

Impl3(Blackboard b) { process(b.getCollectionC()); }

Context

StackExchange Code Review Q#128, answer score: 9

Revisions (0)

No revisions yet.