使用存储库模式的具有多个数据源的架构

Architecture with several data sources using Repository pattern

我有一个使用 MVP 架构的项目。 该项目使用存储库模式。

我有两个数据源,第一个来自远程 JSON Api 到 PollutionApiService,第二个只是我从 XML 获得的微不足道的数据资产文件夹中的文件:air_quality_levels.xml。网络数据包含实时污染级别,XML 文件包含这些污染级别的限制标准。

现在我只是为 JSON Api 实现了一个存储库,它看起来像这样:

界面

public interface Repository {
    Observable<Aqicn> getPollutionLevelsFromNetwork(String city, String authToken);
   Observable<Aqicn> getPollutionLevels(String city, String authToken);
}

Class

public class PollutionLevelsRepository implements Repository {
    private PollutionApiService pollutionApiService;
    private static Observable<Aqicn> pollutionData = null;


    public PollutionLevelsRepository(PollutionApiService pollutionApiService) {
        this.pollutionApiService = pollutionApiService;
    }

    @Override
    public Observable<Aqicn> getPollutionLevelsFromNetwork(String city, String authToken) {
        pollutionData = pollutionApiService.getPollutionObservable(city, authToken);
        return pollutionData;
    }

    @Override
    public Observable<Aqicn> getPollutionLevels(String city, String authToken) {
        return getPollutionLevelsFromNetwork(city, authToken);
    }
}

我是否应该对将从资产文件夹中的 XML 文件中获取的数据使用相同的存储库(添加更多方法)?

如果我必须使用两个存储库,我应该如何命名第二个存储库接口?我从来没有多个存储库,所以我总是使用接口的通用名称 "Repository"。我不能给它取与 class 相同的名称,也不能添加 "I" 前缀,因为我读到这是不好的做法......或者我应该保留这个 "Repository" 名称并放另一个包中的新存储库 ?

这是我的实际项目结构,请注意,我按功能打包,但我将两个存储库放在公共包中,因为它获取将由我的两个功能(甜甜圈和污染级别)使用的数据:

如果您对总体架构有简短的相关建议,欢迎提出。

存储库的想法是作为数据实际来源与使用它的业务逻辑代码之间的抽象。您的业​​务逻辑既不知道也不关心数据是通过网络、xml 还是来自其他任何地方。这允许将来具有灵活性,以便您可以自由更改获取数据(缓存、离线存储等)的实现,同时仍保持存储库的原始合同。

我倾向于为每个 'type' 数据创建一个单独的存储库。在您的情况下,网络请求和 xml 都是污染级别数据,因此我会将它们放在同一个存储库中。但是,如果您需要用户数据,那么我会单独制作一个 class 来处理这个问题(可能是 AccountRepositoy)。

考虑到以上几点,我将创建一个 class PollutionLevelsRepository,如下所示:

public class PollutionLevelsRepository {

    private PollutionHttp pollutionHttp;
    private PollutionXml pollutionXml;

    public PollutionLevelsRepository(PollutionHttp pollutionHttp, PollutionXml pollutionXml) {
        this.pollutionHttp = pollutionHttp;
        this.pollutionXml = pollutionXml;
    }

    public Observable<Aqicn> getRealTimePollutionLevels(String city) {

        // currently this method runs the http request
        // note that I have removed the auth token - this is a network
        // implementation detail and probably shouldn't be part of the public api
        return pollutionHttp.getPollutionLevels(city);
    }

    public Observable<Aqicn> getPollutionLimitStandard(String city) {

        // this method would return data from the xml
        return pollutionXml.getPollutionLimit(city);
    }
}

请注意,方法名称并未指明数据的来源。您可以随时更改此设置。此外,我认为没有理由实现接口。其他人可能不同意这一点,但由于您只会有一个实现,我会称之为 YAGNI 并说它只会引入不必要的复杂性。

这两个 classes PollutionHttp & PollutionXml 是你的模型 classes 负责实际执行 http 请求并解析来自 xml 的数据(随心所欲地称呼他们!)