Laurent
Laurent

Reputation: 1749

Architecture with several data sources using Repository pattern

I have a project using MVP architecture. This project use the Repository pattern.

I have two data sources, the first one come from a remote JSON Api through PollutionApiService, the second is just trivial data I get from an XML file in the assets folder : air_quality_levels.xml. The network data contains real time pollution levels, the XML file contains the limits standard for these pollution levels.

For now I just have a Repository implemented for the JSON Api, it looks like this :

Interface

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);
    }
}

Should I use the same repository (adding more methods) for the data I will get from the XML file in the assets folder ?

If I have to use two repositories, How should I name this second repository interface ? I never had several repositories so I always use the generic name "Repository" for the interface. I can't give it the same name as the class and can't add a "I" prefix as I read it's bad practice... Or should I keep this "Repository" name and put the new Repository in another package ?

This is my actual project structure, note that I package by features but I put my both repositories in the common package because it gets data that will be used by my both features (donut and pollutionlevels) :

enter image description here

If you have short relevant suggestions about the architecture in general they are welcome.

Upvotes: 5

Views: 4838

Answers (1)

Jahnold
Jahnold

Reputation: 7683

The idea of a Repository is to act as an abstraction between where the data is actually coming from and the business logic code which consumes it. Your business logic should neither know or care whether data is coming via the network, xml or from anywhere else. This allows flexibility in future so that you are free to make changes to the implementation of fetching the data (caching, offline storage, etc) whilst still maintaining the original contract of the Repository.

I tend to create a separate Repository for each 'type' of data. In your case both the network request and the xml are pollution level data so I would put them in the same Repository. If however you needed to have user data then I would make a separate class to deal with this (AccountRepositoy possibly).

With the above in mind I would create a class PollutionLevelsRepository as follows:

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);
    }
}

Note that the method names give no indication of where the data is coming from. You are free to change this at any time. Also I see no reason to implement an interface. Others might disagree with this but as you're only going to have one implementation I would call YAGNI and say that it just introduces unnecessary complexity.

The two classes PollutionHttp & PollutionXml are your model classes responsible for actually doing the http request and parsing the data from xml (call them what you want!)

Upvotes: 8

Related Questions