我试图找出存储从数据库中检索的对象集合的位置,这些对象是应用程序运行所必需的。例如,我正在尝试重新设计使用Report
和Parameter
对象的报表应用程序。这些对象以XML格式存储在数据库中。在最简单的级别,定义的集合可以存储为Dictionary<string, string>
(对象键,对象定义XML)。
我想实现一个工厂模式来处理从XML定义中创建这些对象。
IReport GetReport(string reportName)
IParameter GetParameter(string parameterName)
这些方法要求工厂存储报告和参数的集合。
所以,我的问题是:
IReport GetReport(string reportDefinition)
答案 0 :(得分:2)
您的应用程序应该是持久无知的,因此您的报表工厂(或存储库对于数据存储的外观来说是一个更好的术语,实际上它是数据访问对象而不是真正的存储库)不应采用报表定义格式。
Get方法应该为报告采用唯一标识符(这应该是报告名称吗?)并返回包含报告实体的所有值的DTO类型。
您可以使用抽象工厂模式来实现存储库的不同实现,执行XML反序列化的实现,以及单元测试的模拟实现。
如果您已经有一个数据库作为数据存储,那么您的存储库不需要将集合存储在内存中,尽管您可能希望将缓存添加到存储库中,如果您的应用程序正在运行,则再次更容易切换抽象。
答案 1 :(得分:2)
您可以通过多种方式对其进行结构化,这些方式都符合SRP (Single Responsibility Principle)。
一种方法如下:拥有一个接口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
个实例,而另一个服务则负责实际获取报告定义。
对于单元测试,您可以创建IReportDefinitionRetrievalService
的模拟,它可以执行您想要的任何操作(例如,在字典中查找定义)。看看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());
}
答案 2 :(得分:0)
1.工厂应该存储对象的集合,还是应该只负责从定义中创建对象, 将方法更改为IReport GetReport(string reportDefinition)
以上都不是。工厂是具体的实现选择器。它是作为静态方法实现的,它根据输入实例化具体对象。您已经完成了使用接口和名称正确解耦的工作。停在那里。
static IReport GetReport(string reportName)
IReport concreteReport = Factory.GetReport("myReportName")
通过单元测试对工厂进行测试非常简单。您可以创建一个报告名称数组,并通过反射或一些任意已知的断言检查IReport
是否是正确的实现。依赖注入是一个完全不同的主题。