Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Design Pattern to access same data from different sources

I have this problem: I have data to save both local and both remotely on cloud, in order to be able to get them from every device. Now, if there is connection I have to load them from remote (and eventually update them if there was an update without connection) and save any changes also locally, if there is no connection I can and have to use only the local source. I first thought of a Strategy but it is evidently wrong, than I thought of a Proxy but I don't know if it fits. During my design I created a managerPreferitiDB that on the situation (probably with a State pattern) accesso to localPreferitiDB (for local access) and/or cloudPreferitiDB (for remote access). I Thought that I should probably have a preferitiRetriever Interface, implemented by both of them and then having two or more preferitiRetriever in my managerPreferitiDB Proxy.

Any advices? Is there a better pattern that suits this? I'm using Java for Android, Thanks

like image 227
user1868607 Avatar asked Dec 15 '15 09:12

user1868607


People also ask

Which design pattern provides a way to access the elements?

Definition. The essence of the Iterator Pattern is to "Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.".

Which design pattern works on data?

Explanation: Command pattern is a data driven design pattern.


2 Answers

There is no GoF (Gang of Four) pattern that address your scenario. The GoF patterns are more low level while you're facing a more complex issue that involves a local cache and a remote storage. GoF patterns does not address networking.

Maybe you can find something useful in the Catalog of Patterns of Enterprise Application Architecture by Fowler, for example Remote Facade and Data Transfer Object, but these are only a part of the possible solution.

I think that this is a matter of subsystem design so you need to define a suitable abstraction and then use GoF or other patterns where appropriate for the implementation details.

The abstraction you'll define to represent the cache / remote storage subsystem does not have to respond to a specific single pattern; as I'm aware of, there isn't a public available blueprint of such a system.

like image 56
mxb Avatar answered Oct 23 '22 12:10

mxb


In my opinion, there are two problems which your api design has to solve.

Firstly, Repository implementations should be abstracted from its clients. By doing that, it allows you to make changes to Repository implementation without affecting the existing code, the clients of Repository.

Secondly, we should have two separate implementations which are CloudRepository and LocalRepository. Because they have very specific responsibilities, one deals with a Cloud-related persistent storage, and the other deals with a Device-related persistent storage. I'm not a mobile developer so I assume these two implementations might be complicated and swapping Local or Cloud persistent technologies are likely to happen

Here is the design solution. It's somehow a mixture of the Strategy, Proxy patterns.

The first one is simple. As long as you inject a concrete implementation of Repository into it clients through constructors or setters, then the clients are not coupled to any repository. In this case, I strongly suggest constructor injection because clients cannot function probably without a Repository.

public class Client {
    private final Repository repository;
    public Client(Repository repository) {
       this.repository repository;
    }
}

For the second problem, we just need one more Repository implementation which I call SwitchRepository. Basically, it coordinates Cloud, Local repositories to accomplish your goal of data access which depends on the Internet connection status.

public SwitchRepository implements Repository {
     private Repository cloudRepository;
     private Repository localRepoistiry;

     public SwitchRepository(Repository cloudRepository, Repository localRepository) {
        this.cloudRepository = cloudRepository;
        this.localRepository = localRepository;
    }
    public void save(Data data) {
        // do whatever we want here
        if(isInternetConnected()) {

        } else {

        }
    }

  // the same for any operations of the Repository interface
}

To sum up:

public static void main(String[] args) {
    Repository localRepository = new LocalRepository();
    Repository cloudRepository = new CloudRepository();
    Repository switchRepository = new SwitchRepostitory(cloudRepository, localRepository);
    Client client = new Client(switchRepository);
}
like image 41
Hung Tran Avatar answered Oct 23 '22 11:10

Hung Tran