I'm trying to make a design based on the Uncle Bob's Clean Architecture in Android.
The problem:
I'd like to solve is how to make the changes generated in one repository to be reflected in other parts of the app, like other repositories or Views.
The example
I've designed a VERY simplified example for this example. Please notice that boundary interfaces has been removed to keep the diagrams small.
Imagine an app that shows a list of videos (with title, thumnail and like count), clicking a video you can see the detail (there you can like/dislike the video).
Additionally the app has an statistics system that counts the number of videos the user liked or disliked.
The main classes for this app could be:
The target
Now imagine you check your stats, then navigate the list of videos, open the detail of one, and click the like button.
After the like is sent to the server, there are several elements of the apps that should be aware of the change:
StatsRepository
may want to update/invalidate the caches after voting a new videoThe Question
What are the common patterns to solve this kind of communication? Please make your answer as complete as you can, specifying where the events are generated, how they get propagated though the app, etc.
Note: Bounties will be given to complete answers
Typically, for n:m communication (n senders may send a message to m receivers, while all senders and receivers do not know each other) you'll use a publish/subscribe pattern. There are lots of libraries implementing such a communication style, for Java there is for example an EventBus implementation in the Guava library. For in-app communication these libraries are typically called EventBus or EventManager and send/receive events.
Suppose you now created an event VideoRatedEvent
, which signals that a user has either liked or disliked a video.
These type of events are referred to as Domain Events. The event class is a simple POJO and might look like this:
class VideoRatedEvent {
/** The video that was rated */
public Video video;
/** The user that triggered this event */
public User user;
/** True if the user liked the video, false if the user disliked the video */
public boolean liked;
}
Now each time your users like or dislike a video, you'll need to dispatch a VideoRatedEvent
.
With Guava, you'll simply pass an instantiated event object to object to EventBus.post(myVideoRatedEvent)
.
Ideally the events are generated in your domain objects and are dispatched within the persisting transaction (see this blog post for details).
That means that as your domain model state is persisted, the events are dispatched.
In your application, all components affected by an event can now listen to the domain events.
In your particular example, the VideoDetailView
or StatsRepository
might be event listeners for the VideoRatedEvent
.
Of course, you will need to register those to the Guava EventBus with EventBus.register(Object)
.