'Final' keyword is a powerful modifier used in Java and in other OOP languages to denote that a given construct is no more extensible. Rather than a mere keyword, I would argue it's a 'key trade off' decision, by looking at the future and arriving at the conclusion whether we should really allow further extensibility in a given construct or limiting it.
The final keyword is applied at 3 levels; at class level, at method level and at field level. It's a simple decision to decide whether or not one should apply the 'final' keyword at method or field level, so in this short note, I am focusing on the 'final' at the class level.
By using the 'final' keyword in front of a class, you are essentially sealing the class off and preventing any further 'extensibility' of it, violating one of the SOLID principles, 'open to extension and closed to modification'. This violation means that you cannot create a subclass to add the new behavior in the runtime if the business ever called for it.
Therefore, now you understand that this is a critical decision in terms of the design and not a simple 'good to have' decision. This means we should have solid and good reason to apply this keyword.
'Final' keyword is used mainly in frameworks, system codes and libraries to 'purposefully' prevent adding new runtime behavior via extension with the hope of preventing corruption since developers with either malicious intentions or with lack of knowledge can add half-baked code into subclasses. A good example is the 'String.class' in Java, which is a sealed class with 'final' keyword. Such sealing is needed for String class to ensure no misbehaving subclasses are created, which will corrupt the data in the String pool or the system in general. Similarly, many frameworks and libraries have their critical classes with algorithms/processes sealed off with final to ensure no subclass with 'wrong behavior' is injected.
So what is the best way to use 'Final'?
1. Know the nature of your class and check for yourself whether sub classing can have bad consequences and deviations from the intended behavior, which will drive you to an educated decision.
2. Apply 'final' keyword at more granular levels such as method levels to keep the critical functionality sealed while providing extension to the non critical functionality. A good example is the 'Template Design Pattern'. In the example Template Pattern below observe how the algorithm is sealed off from modification while the steps have been delegated to the subclasses for overriding and extension. This is a good balance of both security and extensibility.
Abstract Class Parent{
public final executeAlgorithm() // NOT ALLOWED TO BE EXTENDED
{
stepOne();
stepTwo();
}
protected abstract stepOne(); //FREELY ALLOWING EXTENSION
protected abstract stepTwo(); //FREELY ALLOWING EXTENSION
}
Class child extends Parent{
protected stepOne() {//code }
protected stepTwo() {// code}
}
Comments
Post a Comment