Table of contents
In this article, we'll go over the template method pattern and take a look at the Android ViewModel class as an example implementation of the pattern.
The ViewModel
The ViewModel
is an application architecture component we've come to love and talk about -- VM in MVVM architecture. The Android team has packaged a ViewModel in the lifecycle library that we can subclass to model data for our views. From the docs:
A ViewModel is always created in association with a scope (a fragment or an activity) and will be retained as long as the scope is alive. E.g. if it is an Activity, until it is finished.
If the ViewModel is created in association with a scope, wouldn't it be nice to know when the scope is destroyed? Well, it is. Enter the Template Method Pattern.
The Template Method Pattern
The Template Method Pattern is a behavioral pattern in which a step in an operation is deferred to subclasses - a classic case for code reuse. The superclass defines a "hook" with some default behavior and subclasses can extend it if necessary.
Looking at the definition of the Android ViewModel, we find a method clear()
.
public abstract class ViewModel {
... // other important things
@MainThread
final void clear() {
... // omitted clean-up logic
onCleared();
}
protected void onCleared() {
// the hook
}
}
clear()
is invoked to perform clean-up logic and in the end, it calls onCleared()
. (clear() is called when ViewModel scope is destroyed)
The default implementation for onCleared()
is a no-op in the parent class but the protected keyword in the signature tells us that subclasses can have a go at it - and that's our hook, the template method pattern. Any code you put in the overridden method on a ViewModel subclass will be invoked when the ViewModel's scope is destroyed.
Example
Take an example where you have a subscription from some implementation of the reactive streams specification. onCleared()
then becomes a suitable last-resort callback for canceling the subscription. Thanks to the template method pattern, we know it is invoked when the ViewModel is destroyed.
class PatternViewModel : ViewModel() {
private val subscription: Subscription = ...
override fun onCleared() {
subscription.cancel()
}
}
Conclusion
Design patterns make the software we write reusable, and clearer to read and maintain. The template method pattern occurs over and over again in production software and is a useful pattern to learn and use.
Happy coding.