带(或不带)IProgress 的存储库接口

Repository Interface with (or without) IProgress

我有一个存储库接口(简化的示例代码):

public interface IPersonRepository
{
    Task<PersonDTO> Get();
}

有两个实现。

一个直接连接到数据库:

public SqlPersonRepository : SqlRepository, IPersonRepository
{
    public SqlPersonRepository(IDbConnectionProvider dbCon) : base(dbCon) { }

    public async Task<PersonDTO> Get()
    {
        // use dbCon and dapper to get PersonDTO from database
    }
}

还有一个通过网络远程访问 api:

public ApiPersonRepository : ApiRepository, IPersonRepository
{
    public ApiPersonRepository(IApiConnectionProvider apiCon) : base(apiCon) { }

    public async Task<PersonDTO> Get()
    {
        // use apiCon (contains base url and access token) to perform an HTTP GET request
    }
}

接口在这里很有意义,因为服务器可以使用SqlPersonRepository。而远程(本机)客户端可以使用 ApiPersonRepository。对于大多数用例,这就是我所需要的。

但是,我的应用程序支持从服务器提取数据子集,以便客户端应用程序可以在离线时 运行。在这种情况下,我不只是抓取一个人,而是抓取大量数据(几兆字节到几十兆字节),这些数据会通过慢速移动连接多次下载。我需要传递一个 IProgress 实现,以便我可以报告进度。

在那些情况下,我需要一个如下所示的 ApiDatabaseRepository

public ApiDatabaseRepository : ApiRepository, IDatabaseRepository
{
    public ApiDatabaseRepository(IApiConnectionProvider apiCon) : base(apiCon) { }

    public async Task<DatabaseDTO> Get(IProgress<int?> progress)
    {
        // use apiCon (contains base url and access token) to perform an HTTP GET request
        // as data is pulled down, report back a percent downloaded, e.g.
        progress.Report(percentDownloaded);
    }
}

然而 SqlDatabaseRepository 不需要使用 IProgress(即使 Dapper 可以报告数据库查询的进度,我认为它不能)。无论如何,我不担心直接查询数据库时的进度,但在进行 API 调用时我担心。

所以简单的解决方案是 SqlDatabaseRepository 实现接受 IProgress 参数,默认值为 null,然后实现方法忽略该值。

public SqlDatabaseRepository : SqlRepository, IDatabaseRepository
{
    public SqlDatabaseRepository(IDbConnectionProvider dbCon) : base(dbCon) { }

    public async Task<DatabaseDTO> Get(IProgress<int?> progress = null)
    {
        // use dbCon and dapper to get DatabaseDTO from database
        // progress is never used
    }
}

但这闻起来很有趣。当事情闻起来好笑的时候,我想知道我是不是做错了什么。此方法签名会指示将报告进度,即使它不会。

在这种情况下我应该使用设计模式还是不同的架构?

过于简单化,您基本上有 2 个选择:是否具有一致的界面。

当然还有其他可能适用于此的设计模式(例如,一些装饰器和工厂方法),但我认为它们有些矫枉过正。

如果您坚持需要一致接口的一般规则,我认为拥有“未完全实现”的回调技术并不是那么糟糕。您也可以考虑只实施它 - 或者至少:使其成为 return 有意义的东西。

我肯定会避免使用某种类型的 2 个不同接口的结构。尽管有时这是更好的选择(当检查某物是否支持某物时),例如;测试硬件组件是否可用 - 我认为在您的场景中它是矫枉过正。它还会在调用方放置更多逻辑,除非您只想在这种情况下打开 process-dialog 屏幕,否则我会避免它。

最后一点:还有其他进度报告模式,例如使用事件,或者传入可选的回调方法。后者看起来像您的解决方案,但实际上有点不同。

最终你仍然会遇到同样的问题,但可能值得考虑。


还有更多解决方案 - 但鉴于您提供的上下文,我不确定它们是否适用。请记住,这是高度基于意见的。