首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >动态报表系统的软件体系结构

动态报表系统的软件体系结构
EN

Software Engineering用户
提问于 2021-08-09 09:33:14
回答 1查看 392关注 0票数 -2

我必须创建一个基于数据库中数百个不同表的报告系统(这意味着大量的报告),我想知道最佳实践和/或您对此的疯狂想法。

以下是详细信息:

  • 我必须生成许多不同的报告,(目前定义了大约50种报告类型,但这个数字将来还会增加),比如不同品牌的发动机参数变化、价格、利润等(在预选的时间内)。
  • 每个品牌在数据库中都有不同数量的表,显然对同一件事物有不同的字段名。例如:宝马有一个台式机,其字段名为cc(用于发动机排量),但福特在一个名为“cu”的表中存储了相同的内容。另一方面,价格和销售储存在一个表中,丰田的情况下,在5个表(外键链接)的情况下,马自达。

最简单的解决方案是为每个品牌分别实现每一份报告,但这将是一项耗时的工作,而且几乎是重复的工作,所以我想避免这种方法。

我正在考虑一种“流水线”风格的体系结构(见附件图像),在这里,我只是为每个片段定义了一些规则,而且无论输入参数如何,相同的算法都可以计算结果。这样,如果我必须为劳斯莱斯显示一个新的报告,我只是定义一些规则,我得到的结果。关于规则,我在考虑每个品牌的表定义、字段映射等等。

这个解决方案的问题是,我必须为每一步实现某种解释器,分析和执行规则集,这些规则集是危险的,不可维护的,而且我不确定它是否具有可伸缩性。是否有其他避免重复工作的方法或最佳做法?

EN

回答 1

Software Engineering用户

发布于 2021-08-09 09:53:46

基于所提供的信息,一个简单的接口将满足您的可重用需求。

注意:人们可能会争论使用基类(抽象与否)而不是接口。我建议错误地使用不支持多重继承的语言的接口,或者当所需的契约不需要基本实现时。

例如:宝马有一个台式机,其字段名为cc(用于发动机排量),但福特在一个名为“cu”的表中存储了相同的内容。

您在这里已经确定,虽然数据的存储方式不同,但您希望处理相同的数据(一旦检索到)。检索到的数据并不是特定于给定制造商的,因此您可以创建一个数据实体来表示它:

代码语言:javascript
复制
public class Car
{
    public string Make { get; set; }
    public string Model { get; set; }
    public int CC { get; set; }
}

这只是一个基本的例子。

但是,每个制造商对数据的获取是不同的,因此您的存储库将有明显的不同。尽管如此,他们有着相同的可重用期望:检索汽车。这就是我们定义接口的原因:

代码语言:javascript
复制
public interface ICarRepository
{
    IEnumerable<Car> GetAll();
}

当然,您可以扩展这个接口,例如GetByEngineCC(int minCC)。这取决于你需要什么。

然后,这可以由特定于制造商的存储库实现,它们各自具有不同的私有逻辑来获取所需的数据。

代码语言:javascript
复制
public class FordCarRepository : ICarRepository
{
    public IEnumerable<Car> GetAll()
    {
        // fetch from the Ford tables
    }
}

public class BmwCarRepository : ICarRepository
{
    public IEnumerable<Car> GetAll()
    {
        // fetch from the BMW tables
    }
}

这确保您可以编写适用于所有可能的制造商的报表生成器逻辑。例如:

代码语言:javascript
复制
public void PrintReport(ICarRepository repo)
{
    var cars = repo.GetAll();

    foreach(var car in cars)
    {
        Console.WriteLine($"{car.Make} - {car.Model} - {car.CC}cc");
    }
}

请注意,如果这些制造商的存储库实现了所需的接口,那么这个报告逻辑是如何为所有制造商工作的。

这是如何处理内部不同实现(即唯一的数据获取)的核心原则,但使用外部通用处理(即通用报告)。现在,您可以通过创建额外的具体存储库将新的制造商添加到混合产品中,但是不需要更改其他代码,这是理想的目标。

另一方面,价格和销售储存在一个表中,丰田的情况下,在5个表(外键链接)的情况下,马自达。

这里也有同样的故事:

  1. 假设销售数据是相同的(一旦检索到),创建一个可重用的SalesFigure DTO
  2. 用适当的方法(例如,ISalesRepository )定义一个GetSalesForYear(int year)接口
  3. 创建实现ISalesRepository的特定于制造商的销售存储库
  4. 编写您的公共逻辑,以便它可以使用ISalesRepository对象,而不是特定于制造商的存储库类型。

这样,如果我必须为劳斯莱斯显示一个新的报告,我只是定义一些规则,我得到的结果。

这不是“规则”。这是一个不同的实现。你的基本想法是正确的,但我建议不要把它称为规则,因为人们会误解你的意图。

本质上,您所要做的就是添加一个特定于Rolls的存储库,它实现了相同的接口(cfr步骤3)。

注意:由于您谈到了数据库表,因此这个示例使用了使用相同接口的不同的具体存储库。在其他情况下,在BLL而不是DAL上实现这个接口可能更有意义。但是,无论您在哪个层实现它,它都是相同的原则。

票数 1
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/430913

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档