Very interesting, Suguru. Thank you for sharing!
Model-View-Presenter
Comparing it to my Model-View-Presenter variation for Angular, BLoCs are a blend of container components and presenters. I like to group logic into more explicit layers like these:
BLoCs have mixed system concerns. But they could be used as a facade to hide the details of the different layers from the UI artifacts — such as Angular components — using them. But then again, they would be facades, not BLoCs.
When I build container components and presenters, I like to use methods for input and observables for output. I consider it an anti-pattern to expose subjects. Instead I expose their Observable
interface with subject.asObservable()
and add methods to emit values through the internal (private
) subjects.
For example, I could have a basic SearchPresenter
like this:
If I want to add debouncing to the search while removing duplicates, it is easily added to the public observable pipeline:
It becomes obvious that this logic can be reused for searchboxes in different screens (pages) or even different apps and platforms. This is because it is UI behaviour, not integration to persistence or application state.
A component could be using multiple presenters and we only have to add additional operations or modify them in one place.
Back to the BLoC
Getting back to the BLoC design pattern, I would structure it something like this:
The AppSearchRepository
in app/search
is the concrete implementation of the abstract class SearchRepository
from business-logic/search
. It is your search repository but renamed with an App
prefix to prevent name clashing, developer confusion and accidental imports. It has also got Angular dependency injection since a real repository will need dependencies for reading data from a back-end.
The AppSearchBloc
in app/search
extends the class SearchBloc
from business-logic/search
to add Angular dependency injection and lifecycle hooks.
Note that the Angular BLoC wrapper only references the business logic layer.
Now that we have these Angular-fitted software artifacts in place, our SearchComponent
is clean and simple. Nothing more than a UI wrapper around the search BLoC.
Again, I do not like exposing implementation details, so I would usually add properties and methods to the component that delegate to the BLoC. This way, the template will be unaware of the BLoC, just like other components that reference the search component do not have access to the BLoC directly.
Note that both search component implementations only reference the business logic layer, since they reference the abstract search BLoC class.
Putting it all together, we end up with this implementation:
Let me know what you think 🙂