【发布时间】:2011-05-30 02:28:29
【问题描述】:
我正在编写一个流畅的界面,使用如下:
xmlBuilder
.CreateFrom()
.DataSet(someDataSet) //yes I said Dataset, I'm working with a legacy code
.IgnoreSchema()
.Build
IgnoreSchema() 方法可以用WithSchema() 或WithDiffGrame() 代替。这些映射到接受以下枚举的 DataSet 的 WriteXml() 方法:
- XmlWriteMode.WriteSchema
- XmlWriteMode.DiffGram
- XmlWriteMode.IgnoreSchema
我的 fluent 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;
}
}
}
}
这当然可行,但是当我将这段代码与依赖注入一起使用时,我在开头提到的流利界面中的方法遇到了麻烦。以下是这些方法的实现:
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);
}
现在我没有使用依赖注入 (DI),因为我正在更新依赖的 IDataSetXMLFactory 对象。如果我更改代码以使用 DI,该类如何知道要使用 IDataSetXmlFactory 的哪个实现?如果我正确理解 DI,则需要在调用堆栈的更高层(特别是在组合根处)做出该决定,但在那里的代码不知道需要哪个确切的实现。如果我在上述方法中使用 DI 容器来解析(定位)所需的实现,那么我将使用 DI 容器作为服务定位器,这被认为是一种反模式。
此时,将枚举传递给 IXmlDataSetFactory 实例上的 xmlFactory.CreateXmlDocument() 方法会容易得多。这当然要容易得多,代码也更少,但我敢肯定,这个问题以前在使用状态模式和 DI 时已经遇到过。有什么方法可以解决这个问题?我是 DI 新手,已开始阅读 Dependency Injection in .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();
}
除了上面提到的IDataSetXMLFactory,我还有以下扩展方法:
static class XmlDocumentExtensions
{
[Extension()]
public static void InsertSchema(XmlDocument document, XmlSchema schema)
{
...
}
}
static class XmlSchemaExtensions
{
[Extension()]
public static string ToXmlText(XmlSchema schema)
{
...
}
}
还有这些类:
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
}
}
【问题讨论】:
标签: .net dependency-injection enums fluent-interface