依赖注入和Fluent API - 遇到一些问题

Mat*_*att 3 .net enums dependency-injection fluent-interface

我正在编写一个流畅的界面,使用如下:

xmlBuilder
    .CreateFrom()
    .DataSet(someDataSet) //yes I said Dataset, I'm working with a legacy code
    .IgnoreSchema()
    .Build
Run Code Online (Sandbox Code Playgroud)

IgnoreSchema()方法可以是WithSchema()WithDiffGrame()代替它.这些映射到WriteXml()接受以下枚举的DataSet 方法:

  • XmlWriteMode.WriteSchema
  • XmlWriteMode.DiffGram
  • XmlWriteMode.IgnoreSchema

我的流畅API调用了将从数据集创建XML的各种工厂对象.我有一个具有核心功能的抽象类型,然后是3个派生类型,它们反映了实现该WriteXmlFromDataSet方法的各种状态(我相信这种方法称为状态模式).这是抽象基类:

public abstract class DataSetXmlBaseFactory : IDataSetXmlFactory
{     
    ...    

    protected abstract void WriteXmlFromDataSet(XmlTextWriter xmlTextWriter);

    public XmlDocument CreateXmlDocument()
    {
        XmlDocument document = new XmlDocument();
        using (StringWriter stringWriter = new StringWriter()) 
        {
            using (XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter)) 
            {
                WriteXmlFromDataSet(xmlTextWriter);
                string content = stringWriter.ToString();
                document.LoadXml(content);
                return document;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这当然有效,但是当我使用这个带有依赖注入的代码时,我在开始时提到的流畅界面中的方法遇到了麻烦.以下是这些方法的实现:

public IXmlBuild<T> WithSchema()
{
    var xmlFactory = new DataSetXmlWithSchemaFactory(this.DataSet);
    return GetIXmlBuild(xmlFactory);
}
public IXmlBuild<T> IgnoreSchema()
{
    var xmlFactory = new DataSetXmlIgnoreSchemaFactory(this.DataSet);
    return GetIXmlBuild(xmlFactory);
}
public IXmlBuild<T> WithSchemaAndDiffGram()
{
    var xmlFactory = new DataSetXmlWithDiffGramFactory(this.DataSet);
    return GetIXmlBuild(xmlFactory);
}
private static IXmlBuild<T> GetIXmlBuild(IDataSetXmlFactory xmlFactory)
{
    string content = xmlFactory.CreateXmlDocument().InnerXml;
    return new clsXmlDataSetBuild<T>(content);
}
Run Code Online (Sandbox Code Playgroud)

现在我没有使用依赖注入(DI),因为我正在新建依赖IDataSetXMLFactory对象.如果我更改代码以使用DI,那么该类将如何知道要使用哪个IDataSetXmlFactory实现?如果我正确地理解了DI,则需要在调用堆栈(特别是在组合根)上更高地做出该决定,但在那里代码将不知道需要哪个确切的实现.如果我使用DI容器来解析(定位)上述方法中所需的实现,那么我将使用DI容器作为服务定位器,这被​​认为是反模式.

此时,将枚举传递给xmlFactory.CreateXmlDocument()IXmlDataSetFactory实例上的方法要容易得多.这肯定更容易,而且代码更少,但我确信这个问题之前已经遇到过状态模式和DI.有什么方法可以解决这个问题?我是DI的新手,已经开始阅读.NET中的依赖注入,但尚未阅读有关此特定问题的任何内容.

希望,我只是错过了一小块拼图.


更新(基于Mark Seemann的回答)

下面的界面的语义模型会是什么样的?例子将不胜感激.

public interface IXmlBuilder<T>
{
    IXmlSourceContent<T> CreateFrom();
}

public interface IXmlSourceContent<T>
{
    IXmlOptions<T> Object(T item);
    IXmlOptions<T> Objects(IEnumerable<T> items);
    IXmlDataSetOptions<T> DataSet(T ds);
    IXmlBuild<T> InferredSchema();
}

public interface IXmlOptions<T> : IXmlBuild<T>
{
    IXmlBuild<T> WithInferredSchema();
}

public interface IXmlDataSetOptions<T> : IXmlDataSetSchema<T>
{
    IXmlDataSetSchema<T> IncludeTables(DataTableCollection tables);
    IXmlDataSetSchema<T> IncludeTable(DataTable table);
}

public interface IXmlBuild<T>
{
    XmlDocument Build();
}

public interface IXmlDataSetSchema<T>
{
    IXmlBuild<T> WithSchemaAndDiffGram();
    IXmlBuild<T> WithSchema();
    IXmlBuild<T> IgnoreSchema();
}
Run Code Online (Sandbox Code Playgroud)

除了上面提到的IDataSetXMLFactory,我还有以下扩展方法:

static class XmlDocumentExtensions
{    
    [Extension()]
    public static void InsertSchema(XmlDocument document, XmlSchema schema)
    {
       ...    
    }    
}

static class XmlSchemaExtensions
{    
    [Extension()]
    public static string ToXmlText(XmlSchema schema)
    {
       ...    
    }    
}
Run Code Online (Sandbox Code Playgroud)

和这些类:

public class XmlFactory<T>
{
    ...

    public XmlFactory(IEnumerable<T> objects)
    {
        this.Objects = objects;
    }

    public XmlDocument CreateXml()
    {
        // serializes objects to XML
    }
}

public class XmlSchemaFactory<T> : IXmlSchemaFactory<T>
{
    public XmlSchema CreateXmlSchema()
    {
        // Uses reflection to build schema from type
    }
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*ann 6

在我看来,您正在发现根据API所针对的对象模型定义Fluent API的局限性.正如Jeremy Miller指出的那样,让Fluent API构建一个语义模型通常会更好,然后可以使用它来构建所需的对象图.

这是我分享的经验,我发现它有助于弥合Fluent API和DI之间的明显差距.


基于最初的Fluent API,语义模型可能就像这样简单:

public class MySemanticModel
{
    public DataSet DataSet { get; set; }
    public bool IgnoreSchema { get; set; }
    // etc...
}
Run Code Online (Sandbox Code Playgroud)