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

时间:2018-07-25 20:19:58

标签: c# asp.net .net .net-core factory-pattern

我想在程序中实现工厂模式,但我不习惯。实现这种factory和Execute()方法(将调用具有各种不同参数的其他方法)的最佳实践是什么?

我有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;
        }
    }
}

switch情况下使用的每个类都从Execute()实现IStep interface方法

但是,每个类为此方法需要不同的参数,因为Execute()方法将用于调用其他方法,例如:

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

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
    }

}

具有Execute()方法的接口,所有类都将实现该方法:

public interface IProcessStep
{
    void Execute();
}

另一个类的方法将需要FileInfo file参数,依此类推。 实现这种工厂和Execute()方法(将调用具有各种不同参数的其他方法)的最佳实践是什么?

3 个答案:

答案 0 :(得分:0)

作为工厂模式的新手,我的建议是每1个接口有1个工厂,然后根据它们的实际功能命名它们,因此ExecuteTest1(int param1),ExecuteTest2(int param1,int param2),等等...

过去,您正在寻找的是抽象工厂模式。

答案 1 :(得分:0)

我使用了策略模式。以下是有助于推动它前进的代码

onAttach()

这是新上课的

 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);
    }
}

您实现一流的TableCountTest

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
    }
}

第二个实现类CompareTest

public class TableCountTest : ITableCountTest,IProcessStep
{
    //... other code

    public void Execute()
    {
        /*   your logic goes here*/
    }
    public void Test(int id)
    {

    }
}

希望这会有所帮助。

答案 2 :(得分:0)

您的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; }
}

您在问题中显示的示例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);

现在,所有步骤的Execute()方法都具有相同的签名,从而使您可以像想要的那样通过通用接口调用它们。请注意,由于每个步骤都接收相同的context对象,因此每个步骤理论上都可以对其进行更改,而后续步骤则以先前步骤已经完成的工作为基础。这可能是有益的,但也可能是缺点。步骤列表变得越长,上下文类变得越复杂,就越容易跟踪在何处设置或更改的内容。如果您使用这种方法,建议您仔细考虑上下文的​​哪些部分应该是可变的,哪些应该是不可变的。

如果出于某种原因,您希望Execute()方法不带问题中显示的参数,那么您可能需要做的就是修改ProcessStepFactory::CreateProcessStep()以始终创建并返回IStep的>新实例,而不使用共享实例,并分配如上所述的单个上下文对象或该方法的现有参数列表的适当组合作为步骤对象的属性。