简体   繁体   English

具有不同输入参数的类的工厂模式设计

[英]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? 实现此类factory和Execute()方法(将调用具有各种不同参数的其他方法)的最佳实践是什么?

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案例中使用的每个类都从IStep interface实现Execute()方法

however, each class needs different parameters for this method as Execute() method will be used to call other methods, ex: 但是,每个类都需要为此方法使用不同的参数,因为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. 另一个类的方法将需要FileInfo file参数,依此类推。 What is the best practice for implementing such factory and Execute() method which will call other methods with various different parameters? 实现此类factory和Execute()方法(将调用具有各种不同参数的其他方法Execute()的最佳实践是什么?

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... 作为工厂模式的新手,我的建议是每个1个接口有1个工厂,然后根据它们的实际功能将它们全部命名,因此ExecuteTest1(int param1),ExecuteTest2(int param1,int param2)等。 。

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 您实现的第一类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 第二个实现类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() ? IStep实现所需的所有这些参数以及当前要传递给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. 假设它们不是完全独立的数据,并且实际上是您要在其上进行处理的某些对象或概念的不同属性,则可以定义一个将这些属性收集到单个单元中的类,然后定义IStep::Execute()及其实现,以接受该类或该类实现的接口的实例。 For instance: 例如:

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. 现在,您所有步骤的Execute()方法都具有相同的签名,从而使您可以像想要的那样通过通用接口调用它们。 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. 请注意,由于每个步骤都接收相同的context对象,因此理论上每个步骤都可以对其进行更改,而后续步骤则以先前步骤已经完成的工作为基础。 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. 如果您使用这种方法,建议您仔细考虑上下文的​​哪些部分应该是可变的,哪些应该是可变的。

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实例。而不是使用共享实例,而是如上所述分配一个上下文对象,或者将该方法的现有参数列表的适当组合分配为步骤对象的属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM