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 方法:
我的流畅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中的依赖注入,但尚未阅读有关此特定问题的任何内容.
希望,我只是错过了一小块拼图.
下面的界面的语义模型会是什么样的?例子将不胜感激.
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)
在我看来,您正在发现根据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)
| 归档时间: |
|
| 查看次数: |
941 次 |
| 最近记录: |