Open-closed principle and Java "final" modifier - java

The open-closed principle states that "Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification".
However, Joshua Bloch in his famous book "Effective Java" gives the following advice: "Design and document for inheritance, or else prohibit it", and encourages programmers to use the "final" modifier to prohibit subclassing.
I think these two principles clearly contradict each other (am I wrong?). Which principle do you follow when writing your code, and why? Do you leave your classes open, disallow inheritance on some of them (which ones?), or use the final modifier whenever possible?

Frankly I think the open/closed principle is more an anachronism than not. It sems from the 80s and 90s when OO frameworks were built on the principle that everything must inherit from something else and that everything should be subclassable.
This was most typified in UI frameworks of the era like MFC and Java Swing. In Swing, you have ridiculous inheritance where (iirc) button extends checkbox (or the other way around) giving one of them behaviour that isn't used (I think it's its the setDisabled() call on checkbox). Why do they share an ancestry? No reason other than, well, they had some methods in common.
These days composition is favoured over inheritance. Whereas Java allowed inheritance by default, .Net took the (more modern) approach of disallowing it by default, which I think is more correct (and more consistent with Josh Bloch's principles).
DI/IoC have also further made the case for composition.
Josh Bloch also points out that inheritance breaks encapsulation and gives some good examples of why. It's also been demonstrated that changing the behaviour of Java collections is more consistent if done by delegation rather than extending the classes.
Personally I largely view inheritance as little more than an implemntation detail these days.

I don't think the two statements contradict each other. A type can be open for extension and still be closed for inheritance.
One way to do this is to employ dependency injection. Instead of creating instances of its own helper types, a type can have these supplied upon creation. This allows you to change the parts (i.e. open for extension) of the type without changing the type itself (i.e. close for modification).

In open-closed principle (open for extension, closed for modification) you can still use the final modifier. Here is one example:
public final class ClosedClass {
private IMyExtension myExtension;
public ClosedClass(IMyExtension myExtension)
{
this.myExtension = myExtension;
}
// methods that use the IMyExtension object
}
public interface IMyExtension {
public void doStuff();
}
The ClosedClass is closed for modification inside the class, but open for extension through another one. In this case it can be of anything that implements the IMyExtension interface. This trick is a variation of dependency injection since we're feeding the closed class with another, in this case through the constructor. Since the extension is an interface it can't be final but its implementing class can be.
Using final on classes to close them in java is similar to using sealed in C#. There are similar discussions about it on the .NET side.

I respect Joshua Bloch a great deal, and I consider Effective Java to pretty much be the Java bible. But I think that automatically defaulting to private access is often a mistake. I tend to make things protected by default so that they can at least be accessed by extending the class. This mostly grew out of a need to unit test components, but I also find it handy for overriding the default behavior of classes. I find it very annoying when I'm working in my own company's codebase and end up having to copy & modify the source because the author chose to "hide" everything. If it's at all in my power, I lobby to have the access changed to protected to avoid the duplication, which is far worse IMHO.
Also keep in mind that Bloch's background is in designing very public bedrock API libraries; the bar for getting such code "correct" must be set very high, so chances are it's not really the same situation as most code you'll be writing. Important libraries such as the JRE itself tend to be more restrictive in order to ensure that the language is not abused. See all the deprecated APIs in the JRE? It's almost impossible to change or remove them. Your codebase is probably not set in stone, so you do have the opportunity to fix things if it turns out you made a mistake initially.

Nowadays I use the final modifier by default, almost reflexively as part of the boilerplate. It makes things easier to reason about, when you know that a given method will always function as seen in the code you're looking at right now.
Of course, sometimes there are situations where a class hierarchy is exactly what you want, and it would be silly not to use one then. But be scared of hierarchies of more than two levels, or ones where non-abstract classes are further subclassed. A class should be either abstract or final.
Most of the time, using composition is the way to go. Put all the common machinery into one class, put the the different cases into different classes, then composit instances to have working whole.
You can call this "dependency injection", or "strategy pattern" or "visitor pattern" or whatever, but what it boils down to is using composition instead of inheritance to avoid repetition.

The two statements
Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.
and
Design and document for inheritance, or else prohibit it.
are not in direct contradiction with one another. You can follow the open-closed principle as long as you design and document for it (as per Bloch's advice).
I don't think that Bloch states that you should prefer to prohibit inheritance by using the final modifier, just that you should explicitly choose to allow or disallow inheritance in each class you create. His advice is that you should think about it and decide for yourself, instead of just accepting the default behavior of the compiler.

I don't think that the Open/closed principle as originally presented allows the interpretation that final classes can be extended through injection of dependencies.
In my understanding, the principle is all about not allowing direct changes to code that has been put into production, and the way to achieve that while still permitting modifications to functionality is to use implementation inheritance.
As pointed out in the first answer, this has historical roots. Decades ago, inheritance was in favor, developer testing was unheard of, and recompilation of the codebase often took too long.
Also, consider that in C++ the implementation details of a class (in particular, private fields) were commonly exposed in the ".h" header file, so if a programmer needed to change it, all clients would require recompilation. Notice this isn't the case with modern languages like Java or C#. Besides, I don't think developers back then could count on sophisticated IDEs capable of performing on-the-fly dependency analysis, avoiding the need for frequent full rebuilds.
In my own experience, I prefer to do the exact opposite: "classes should be closed for extension (final) by default, but open for modification". Think about it: today we favor practices like version control (makes it easy to recover/compare previous versions of a class), refactoring (which encourages us to modify code to improve design, or as a prelude to introducing new features), and developer testing, which provides a safety net when modifying existing code.

Related

Turning abstract class without fields to interface (Java, Sonar rule s1610)

I refer to this rule:
With Java 8's "default method" feature, any abstract class without direct or inherited field should be converted into an interface.
In my perception default + private methods in Java8+ interfaces is a
pure compromise JDK designers took in order to solve a dilemma they faced: they had to introduce new methods (for ex. Map interface)
without breaking old code that used those interfaces (backward
compatibility).
In practice JDK designers introduced implementation inheritance in places
where interface inheritance existed, so potentially they
increased coupling and brittleness of our existing and future code.
In my perception introduced implementation inheritance now diminishes cool nature of interfaces - the multiple inheritance.
I understand why "abstract classes without fields" is mentioned in Sonar rule. By this the authors of the rule do lessen brittleness (but don't eliminate the fact of implementation inheritance). Compare to problems of Scala traits that do permit fields (new Java interfaces look more and more like Scala's traits) - Scala lang designers tried to solve those problems with things like trait linearization, lazy vals, etc.
I'm avoiding arguments like "it is in JDK so it is a pattern", let us speak more at the conceptual level here.
Question: Could anyone explain me why Sonar promotes this, IMHO, flawed rule?
What do we gain by such a rule? What benefit/use case am I missing here?
Thanks.
I don't necessarily agree with the rule, but I see where it's coming from.
The thing is that you don't really lose anything in this case. The only time you'd run into problems with regard to multiple inheritance would be if you implemented several interfaces containing methods with the same signature and different implementations.
However, this is forbidden by Java (you'd need to provide your own implementation of that method), so there is no danger in doing so.
In general, interfaces are more versatile than classes, so it makes sense to use them if possible.
As a counter point, the interface default feature was introduced to allow adding methods to existing interfaces without breaking existing code, but that's not the case here.

Inheritance chain vs multiple extensions

Is inheritance chaining something that should be avoided?
I'm currently in the process of refactoring a java project and I have come across a number of classes (8) which all of them have a shared functionality. So, using the Extract Super Class refactoring, I created a super class with that functionality and passed it to all the sub-classes. Now, 2 of the classes have also a second shared functionality. Should I create another super class which inherits from the first super class and, in turn, is extended by the sub-classes or simply extend multiple classes on the 2 sub-classes?
Thoughts
Even though both options would work, I feel that going for multiple extensions is preferable since it describes and clarifies the responsibilities of the class. Also, we would avoid making continuous super() calls in order to reach the top super class.
On the other hand, maybe having an inheritance chain kinda tidies up the place.
Edit: I understand I stated my problem completely wrong. The 8 classes that are mentioned above are made to abide by the command pattern and as such each one has a different purpose and functionality. I have extracted a super class to avoid code duplication inside their constructors. Two of those classes have also have a little bit more duplicate code (not duplicate functionality, in the sense that they do the same thing). Unfortunately, due to the nature of the project, the fact that I did not write the original code and the tight time schedule do not allow me to completely reconstruct the whole project. It's, let's say, beyond repair for now. But what I can do is patchwork to try to remove duplicate code and tidy the place up a bit.
Super classes should be used when they model a is-a relationship. If the 8 classes are the same entity, a common super class can be used to avoid duplication. Class hierarchies can hurt maintainability quickly and should be as simple as possible. Avoiding duplicate code is not the main concern when introducing them.
As #davidza5 already pointed out, the principle of composition over inheritance applies here. Common functionality should preferably be extracted into classes that model a has-a relationship, which decouples functionality and makes it easier to change later on.
Another aspect: if a refactoring does not work in all cases this does not mean it is the wrong idea. If it leads to good results for the majority, working around the quirks of the exceptions is a good trade off to make.
Both methods seems to be a bad practice in most cases (favorize composition over inheritance). If you can avoid it by using design patterns (facade, composite, adapter,decorator...). If it can't be done in your case the principle of encapsulation and inheritance is what I would apply. So, when necessary chain inheritance.

Which Java language mechanisms allow code reuse and minimize ripple effects?

The questions asks:
Recount all of the java lenguage mechanisms that
(a) Facilitate code reuse, and
(b) Minimize ripple effects due to requirements
changes.
I am not sure if I am understanding this correctly. For (a) I thought it would be Composition, Association and Inheritance, and for (b) I thought it would be Encapsulation and Polymorphism; but I'm not sure if this is what the question asks and I am not sure if I am missing another mechanism. Also I am not sure about what the question mean by "Java language mechanisms" ?
Can someone help me to clarify this, my book really does not do a good job of explaining this.
In my opinion, composition and association aren't Java language mechanisms, they're related to OOP as a concept.
But Interfaces, Abstract classes and Generics are.
Regarding ripple effect, I would go with this definition:
http://www.javapractices.com/topic/TopicAction.do?Id=123
Constants, private fields (Encapsulation) and again Interfaces/Abstract classes (Polymorphism).
A) Methods, Classes and Inheritance. These are the pure language mechanisms. I wouldn't say composition and association are real mechanisms, they are concepts of oop in general and not associated with the java language.
B) Named Constants instead of magic numbers, minimizing visibility. There is no real polymorphism in java as there is in c++ for example. But using Interfaces as references is a really good idea, as the implementations are easily replaceable. It also allows you to make your code more configurable using the factory pattern or even Dependency Injection. This problem and the advantages of using interfaces is well explained in this article.
Again, polymorphism and encapsulation are oop concepts and not associated directly with the java language.

Will inheritance break encapsulation?

Let's say I have a CSV file and I create a class called CsvFile which extends from java.io.File. This class can parse a CSV file and return some data like how many columns are in the file. It can also be used for functions which takes java.io.File as input. Like FileUtils.copyFile(File from, File to).
My colleague thinks I expose too much from inheritance. His idea is to wrap java.io.File by holding it in a private property, instead of inheriting it. He think exposing all public method/property from file breaks encapsulation, but I take it as a benefit since we get all functions in java.io.File for free.
What do you think?
I would rather agree with your colleague: inheriting java.util.File would expose methods that are not applicable to CsvFile objects, such as list(), listFiles(), setExecutable(), and so on.
Making java.util.File a property behind a getter sounds like a better choice: it does not reveal irrelevant operations to the users of your class, and lets you inherit from a base class of your choice.
I think it all depends of the purpose of the class. If you are truly trying to extend the behavior then I would say it makes sense. If you are not extending behavior of File but are just making a CSV object then encapsulation would limit its behaviors to only what it intention is.
You might also consider making it more generic so it can accept a CSV-formatted InputStream or Reader from a wide variety of sources that cannot (or cannot easily) emit to the filesystem. You can still have a java.io.File setter/constructor for convenience.
This is actually a great debate. Your colleague is on the right side of history on this one. In general the question of inheritance comes down to the relationships of is-a vs. has-a. In general it is more flexible to use composition than inheritance. In your case its a close call. After all a csv file isa file. saying csvfile has-a file does not even sound right. What might be considered as well is to do the inheritance but than wrap the inherited file so that only those CSV file methods that you want are exposed. I would also look into some design patterns around this where you want to inherit from A but expose a more limited interface to the world. I am almost sure there is a design pattern for this. just can't remember the name ....
"Either or I think not, but combining both is the way. First inheritance so that the wheel is not reinvented, than to patterns that encapsulate so that the wheel serves its purpose."
Maybe my point of view is too liberal but...
Encapsulation and inheritance are there for a reason. (Watch the 'evolution' from assemblers to high level languages.) That reason is the programmer. With higher level abstractions/paradigms you can write better code. The trick is to define 'better' of course. For me this is maintainability, self documentation and code reuse. That's why I would choose the encapsulation over inheritance in your particular case. Maybe it's a bit more work to write it once, but sooooo much easier to maintain in the future. (Assuming this CSV stuff is part of a bigger project of course.)
The approach your colleague mentions also has the benefit that your API becomes very small by only exposing methods you really need - which makes it clear how to the user how to use your class (you can think of your public API as some sort of documentation).
As to your question
Will inheritance break encapsulation?
Then, according to Joshua Bloch's Effective Java, inheritance always breaks encapsulation:
Unlike method invocation, inheritance violates encapsulation
[Snyder86]. In other words, a subclass depends on the implementation
details of its superclass for its proper function.
Regarding whether you should use inheritance or composition, as many people already said, it depends on if your CsvFile is-a file, in the sense of java.util.File.

Why friend directive is missing in Java?

I was wondering why Java has been designed without the frienddirective that is available in C++ to allow finer control over which methods and instance variables are available from outside the package in which a class has been defined.
I don't see any practical reason nor any specific drawback, it seems just a design issue but something that wouldn't create any problem if added to the language.
Here are a few reasons off the top of my head:
friend is not required. It is convenient, but not required
friend supports bad design. If one class requires friend access to another, you're doing it wrong. (see above, convenient, not required).
friend breaks encapsulation. Basically, all my privates are belong to me, and that guy over there (my friend).
In general i think it was because of the added cognitive complexity and low number of cases in which it creates an improvement.
I would say that the extremely huge number of lines of java in production at this moment can attest that the friend keyword is not really a big loss :).
Please see #dwb's answer for some more specific reasons.
Only a very naive and inexperienced programmer would advocate against friends. Of course it can be misused, but so can public data, yet that capability is provided.
Contrary to popular opinion, here are many cases, in particular for infrastructure capabilities, where friend access leads to BETTER design, not worse design. Encapsulation is often violated when a method is FORCED to be made public when it really shouldn't be, but we are left with no choice because Java does not support friends.
In addition to the aforementioned package visibility, Java also offers inner and anonymous classes which are not only friends by default, but also automatically have a reference to the containing class. Since creating such helper classes is probably the only reasonable way to use friend in C++, Java doesn't need it since it has another mechanism for that. Iterators are a very good example of this.
Completely agree with spaceghost's statement in his answer
Contrary to popular opinion, here are many cases, in particular for infrastructure capabilities, where friend access leads to BETTER design, not worse design.
My example is simple - if a class A has to provide a special "friend" interface to class B in java we have to place them into the same package. No exceptions. In that case if A is a friend of B and B is a friend of C, A has to be a friend of C which isn't always true. This "friendship transitivity" breaks encapsulation more then any problems which C++ friendship could lead to.
Why not simply think that Java requires friend classes to be co-located ? The package-private visibility allows everyone from the same package to access those members. So you're not only limited to explicitly declared friends, but you allow any (existing or future) friend to alter some members that are specifically designed for this purpose (but not your private stuff). You're still able to fully rely on encapsulation.
Just to add to the other answers:
There is the default package visibility in Java. So, you could call all classes in the same package neighbors. In that case you have explicit control of what you show to the neighbors - just members with package visibility.
So, it's not really a friend but can be similar. And yes, this too leads to bad design...
In my opinion some kind of friend feature (not necessarily very similar to C++'s) would be very helpful in some situations in Java. Currently we have package private/default access hacks to allow collaboration between tightly coupled classes in the same package (String and StringBuffer for instance), but this opens the private implementation interface up to the whole package. Between packages we have evil reflection hacks which causes a whole host of problems.
There is a bit of an additional complication in does this in Java. C++ ignores access restrictions whilst resolving function overloads (and similar) - if a program compiles #define private public shouldn't do anything. Java (mostly) discards non-accessible members. If friendship needs to be taken into account then the resolution is more complicated and less obvious.

Categories