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:
For the Videos part/module:
For the Stats part/module:
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
The layers are the main core of a clean architecture. In our app, we will use three layers: presentation, domain, and model. Each layer should be separated and shouldn't need to know about other layers. It should exist in its own world and, at most, share a small interface to communicate.
Advantages of Using Clean ArchitectureYour code is further decoupled (the biggest advantage.) The package structure is even easier to navigate. The project is even easier to maintain. Your team can add new features even more quickly.
Clean architecture is a software design philosophy that separates the elements of a design into ring levels. An important goal of clean architecture is to provide developers with a way to organize code in such a way that it encapsulates the business logic but keeps it separate from the delivery mechanism.
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)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With