Clash Royale CLAN TAG#URR8PPP
Factory pattern design for classes with different input parameters
I want to implement factory pattern in my program but I'm not used to it. What is the best practice for implementing such factory and Execute() method which will call other methods with various different parameters?
I have StepFactory.cs
class
StepFactory.cs
public class ProcessStepFactory: IProcessStepFactory
{
private readonly ITable_table;
private readonly ICompareTest _compareTest;
public ProcessStepFactory(ITable table, ICompareTest compareTest)
{
_table= table;
_compareTest = table;
}
public IProcessStep CreateProcessStep(string stepName, FileInfo file, DateTime s, DateTime d, int id)
{
switch (stepName)
{
case "TABLE":
return _table;
case "COMPARE":
return _compareTest;
default:
return null;
}
}
}
Each class that I use in switch
case implements Execute()
method from IStep interface
switch
Execute()
IStep interface
however, each class needs different parameters for this method as Execute()
method will be used to call other methods, e.x.:
Execute()
compareTest.cs
:
compareTest.cs
public class CompareTest : ICompareTest
{
private readonly IORepository _Ora;
private readonly IPRepository _Pg;
private readonly IRRepository _rPg;
public TableDataCompareTest(
IORepository Ora,
IPRepository Pg,
IRRepository Pg)
{
_connOra = connOra;
_connPg = connPg;
_resultPg = resultPg;
}
public void Execute()
{
CompareTest(int id, DateTime s, DateTime d)
}
public void CompareTest(int parentId, DateTime oraStart, DateTime pgStart)
{
// do stuff
}
}
table.cs
:
table.cs
public class TableCountTest : ITableCountTest
{
private readonly IORepository _Ora;
private readonly IPRepository _Pg;
private readonly IRRepository _rPg;
public TableCountTest(IORepository Ora,
IPRepository Pg,
IRRepository Pg)
{
_connOra = connOra;
_connPg = connPg;
_resultPg = resultPg;
}
public void Execute()
{
Test(id);
}
public void Test(int id)
{
// do stuff
}
}
Interface which has Execute()
method that all classes will implement:
Execute()
public interface IProcessStep
{
void Execute();
}
another class' method will need FileInfo file
parameter and so on.
What is the best practice for implementing such factory and Execute()
method which will call other methods with various different parameters?
FileInfo file
Execute()
3 Answers
3
Being new to the factory pattern, my advice is to have 1 factory per 1 interface and then to be fancy name them all for what they actually do, so ExecuteTest1(int param1), ExecuteTest2(int param1, int param2), etc...
Past that, what you're looking for is the abstract factory pattern.
I used STRATEGY pattern. Below is the code that shall help to take it forward
public class ProcessStepFactory : IProcessStepFactory
{
private readonly ITableCountTest _table;
private readonly ICompareTest _compareTest;
private readonly IStrategyManager _manager; //code added
public ProcessStepFactory(ITableCountTest table, ICompareTest compareTest,IStrategyManager manager)
{
_table = table;
_compareTest = compareTest;
_manager = manager;
}
public IProcessStep CreateProcessStep(string stepName, FileInfo file, DateTime s, DateTime d, int id)
{
return _manager.Process(stepName);
}
}
This is new class introduced
public interface IStrategyManager
{
IProcessStep Process(string stepName);
}
public class StrategyManager : IStrategyManager
{
private Dictionary<string, IProcessStep> dictionary = new Dictionary<string, IProcessStep>();
public StrategyManager()
{
dictionary.Add("TABLE", new TableCountTest());
dictionary.Add("COMPARE", new CompareTest());
}
public IProcessStep Process(string stepName)
{
return dictionary[stepName]; //returns the required object as per stepName
}
}
Your implementing first class TableCountTest
public class TableCountTest : ITableCountTest,IProcessStep
{
//... other code
public void Execute()
{
/* your logic goes here*/
}
public void Test(int id)
{
}
}
And the second implmenting class CompareTest
public class CompareTest : ICompareTest, IProcessStep
{
//... other code
public void Execute()
{
/* your logic goes here*/
}
public void Compare(int parentId, DateTime oraStart, DateTime pgStart)
{
//
}
}
Hope it helps a bit.
What exactly are all of these parameters that your IStep
implementations are going to require, and that you're currently passing to ProcessStepFactory::CreateProcessStep()
? Assuming they're not completely independent data and are in fact different properties of some object or concept on which you want your process steps to operate, you could define a class that collects those properties into a single unit and then define IStep::Execute()
and its implementations to accept an instance of that class, or of an interface that the class implements. For instance:
IStep
ProcessStepFactory::CreateProcessStep()
IStep::Execute()
public interface IProcessContext
{
// Hopefully you're using more descriptive names than these in your actual code...
FileInfo File { get; set; }
DateTime S { get; set; }
DateTime D { get; set; }
int Id { get; set; }
}
The sample Execute()
methods that you showed in your question would look something like this:
Execute()
// In TableCountTest:
public void Execute(IProcessContext context) =>
Test(context.Id);
// In CompareTest:
public void Execute(IProcessContext context) =>
Compare(context.Id, context.S, context.D);
Now all of your steps' Execute()
methods have the same signature, allowing you to invoke them through a common interface like you're going for. Note that because each step receives the same context
object, each step could theoretically make changes to it, with later steps building on the work already done by earlier steps. This can be beneficial, but can also be a drawback; the longer your list of steps becomes, and the more complex your context class becomes, the easier it is to lose track of what gets set or changed where. If you use this approach I'd recommend thinking carefully about which parts of your context should be mutable and which should not.
Execute()
context
If for whatever reason you want your Execute()
methods to take no parameters as shown in your question, then what you'd probably have to do is modify ProcessStepFactory::CreateProcessStep()
to always create and return a new instance of the appropriate IStep
instead of using shared instances, and assign either a single context object as described above or the appropriate combination of that method's existing parameter list as properties of the step object.
Execute()
ProcessStepFactory::CreateProcessStep()
IStep
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
I have used MEF to create and Execute Factory patters with Interfaces. docs.microsoft.com/en-us/dotnet/framework/mef
– Viju
yesterday