1

我试图找出存储从数据库中检索的对象集合的位置,这些对象集合是应用程序运行所必需的。例如,我正在尝试重新设计一个使用ReportParameter对象的报告应用程序。这些对象以 XML 格式存储在数据库中。在最简单的级别,定义的集合可以存储为Dictionary<string, string>(对象键,对象定义 XML)。

我想实现一个工厂模式来处理从它们的 XML 定义创建这些对象。

IReport GetReport(string reportName)
IParameter GetParameter(string parameterName)

这些方法要求工厂存储报告和参数的集合。

所以,我的问题是:

  1. 工厂应该存储对象的集合还是只负责从定义中创建对象,将方法更改为IReport GetReport(string reportDefinition)
  2. 如果工厂应该存储对象,我应该简单地将集合注入工厂类的构造函数吗?
  3. 单元测试——如果我走#2的路线,我想我会把我的测试集合注入工厂,对吧?
4

3 回答 3

2

您的应用程序应该是持久无知的,因此您的报告工厂(或存储库对于数据存储的外观来说是一个更好的术语,实际上它是一个数据访问对象而不是真正的存储库)不应该采用报告定义格式。

Get 方法应采用报表的唯一标识符(这应该是报表名称吗?)并返回具有报表实体所有值的 DTO 类型。

您可以使用抽象工厂模式来实现存储库的不同实现,一个执行 XML 反序列化,一个模拟实现用于单元测试。

如果您已经有一个数据库作为数据存储,则您的存储库不需要将集合存储在内存中,尽管您可能希望将缓存添加到存储库,如果您的应用程序正在处理抽象,则更容易切换出来。

于 2012-08-17T14:38:28.583 回答
2

您可以通过多种方式来构建它,这些方式都遵守SRP(单一责任原则)

一种方法如下:有一个接口,IReportLoadingService,带有一个接收报告标识符并返回IReport实例的方法。

这个的实现IReportLoadingService可以有IReportDefinitionRetrievalService一个依赖,例如

public class ReportLoadingService : IReportLoadingService
{
    private readonly IReportDefinitionRetrievalService _definitionService;

    public ReportLoadingService(IReportDefinitionRetrievalService definitionService)
    {
        _definitionService = definitionService;
    }

    public IReport GetReport(string reportName)
    {
        var reportDefinition = definitionService.GetDefinition(reportName);
        return GenerateReportFromDefinition(reportDefinition);
    }

    private IReport GenerateReportFromDefinition(string definition)
    {
        // Logic to construct an IReport implementation
    }

}

的实时实现IReportDefinitionRetrievalService将访问数据库并返回 XML。现在您ReportLoadingService负责填充IReport实例,而另一个服务负责实际获取报表定义。

对于单元测试,您可以创建一个 MockIReportDefinitionRetrievalService来做任何您想做的事情(例如在字典中查找定义)。查看Moq以获得良好的模拟框架。它将允许您执行以下操作:

[Test]
public void GetReportUsesDefinitionService()
{
    var mockDefinitionService = new Mock<IReportDefinitionRetrievalService>();
    mockDefinitionService.Setup(s => s.GetDefinition("MyReportName")).Returns("MyReportDefinition");

    var loadingService = new ReportLoadingService(mockDefinitionService.Object);

    var reportInstance = loadingService.GetReport("MyReportName");

    // Check reportInstance for fields etc

    // Check the definition service was used to load the definition
    mockDefinitionService.Verify(s => s.GetDefinition("MyReportName"), Times.Once());
}
于 2012-08-17T14:44:17.943 回答
0

1.工厂应该存储对象的集合还是应该只负责从定义中创建对象,将方法更改为IReport GetReport(string reportDefinition)

以上都不是。工厂是一个具体的实现选择器。它被实现为一个静态方法,它根据输入实例化一个具体的对象。您已经完成了与接口和名称正确解耦的工作。停在那里。

static IReport GetReport(string reportName)

IReport concreteReport = Factory.GetReport("myReportName")

通过单元测试来测试工厂是直截了当的。您可以创建一个报告名称数组,并IReport通过反射或一些任意已知的断言检查是否正确实现。依赖注入是一个完全不同的话题。

于 2012-08-17T14:48:05.063 回答