3

tl;dr Can I have a repository depend on another repository, where they both implement the same interface?

I am working on a website analytics system that involves getting data from different sources. One of these sources is very slow for large datasets and the other is deprecated and we are moving away from it.

interface TrafficInterface
{
    public function getVisits(DateTime $from, DateTime $to);
}

I already have an interface (TrafficInterface) for retreiving the data from either source.

class TrafficRepository implements TrafficInterface
{
    private $client;

    public TrafficRepository($apiClient)
    {
        $this->client = $apiClient;
    }

    public function getVisits(DateTime $from, DateTime $to)
    {
        // get data from an API
    }
}

TrafficRepository is used to access the data from the current tracking system.

class LegacyTrafficRepository implements TrafficInterface
{

    public function getVisits(DateTime $from, DateTime $to)
    {
        // get old data that is stored locally
    }
}

LegacyRepository is used to access data from the old system that is stored locally as JSON files.

I want to create further repositorys that use TrafficRepository and LegacyRepository as dependencies.

class CachingTrafficRepository implements TrafficInterface
{

    private $repository;

    public CachingTrafficRepository(TrafficRepository $repository)
    {
        $this->repository = $repository;
    }

    public function getVisits(DateTime $from, DateTime $to)
    {
        // check the cache for data, delegate to the repository if not
        // return data
    }
}

CachingRepository reduces the problem with the slow API. As the data from the API will not change after the current period (day, week, ...) it can be cached forever.

It wraps TrafficRepository and handles adding data to the cache when it is not already there.

class TransitionalTrafficRepository implements TrafficInterface
{
    private $legacy;
    private $caching;

    public TransitionalTrafficRepository(LegacyTrafficRepository $legacy, 
        CachingTrafficRepository $caching)
    {
        $this->legacy = $legacy;
        $this->caching = $caching;
    }

    public function getVisits(DateTime $from, DateTime $to)
    {
        // get data from the relevant repository
        // combine data and return 
    }
}

TransitionalRepository handles combining data from each of the sources so we seem to have a single source for the data.

  • Is there a a name for this system (other than composition)?
  • Are there any problems associated with this?
  • Are there better alternatives?
  • By the way, in the class java.util.time.Instant was added in Java 8. It is a much better "Time" class than previously existed in Java...it may be worth replacing Joda for the standard Java class (depends on the amount/flexibility of your legacy code though) – Ivan Mar 24 '17 at 19:28
4

Is there a a name for this system (other than copmosition)?

Kind of. Having an interface, and then an implementation that implements the interface, while also wrapping another instance of the interface (your CachingTrafficRepository should really work against any TrafficInterface, not just TrafficRepository) is called the Decorator Pattern. Caching is a classic example where it can be used.

Your TransitionalTrafficRepository is the classic Composite Pattern.

Outside of the flexibility note above, these seem like fine cases for these patterns and you're unlikely to find better alternatives - except perhaps eliminating the need for them.

0

Short answer: Yes, your repository can "depend on" another repository.

You may want to look at something like a Data Access Object (DAO).

The point here is that you are hiding HOW you get the data you need. Your code doesn't have to care if the data came from a Legacy Database, a local file, a complex Hadoop back-end, or on-the-fly mocking.

You'll want your deepest/inner-most repo or dependency to define this core DAO interface. Then your other repos just add or define new objects that implement this core DAO interface. You can use Decorators and Composition as necessary in these repos (as @Telastyn suggests).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.