What is the fragile base class problem? - java

What is the fragile base class problem in java?

A fragile base class is a common problem with inheritance, which applies to Java and any other language which supports inheritance.
In a nutshell, the base class is the class you are inheriting from, and it is often called fragile because changes to this class can have unexpected results in the classes that inherit from it.
There are few methods of mitigating this; but no straightforward method to entirely avoid it while still using inheritance. You can prevent other classes inheriting from a class by labelling the class declaration as final in Java.
A best practice to avoid the worst of these problems is to label all classes as final unless you are specifically intending to inherit from them. For those to intend to inherit from, design them as if you were designing an API: hide all the implementation details; be strict about what you emit and careful about what you accept, and document the expected behaviour of the class in detail.

A base class is called fragile when changes made to it break a derived class.
class Base{
protected int x;
protected void m(){
x++;
}
protected void n(){
x++; // <- defect
m();
}
}
class Sub extends Base{
protected void m(){
n();
}
}

It is widely described in below article By Allen Holub on JavaWorld
Why extends is evil.
Improve your code by replacing concrete base classes with interfaces

All of what Colin Pickard said is true, but here I want to add some of the best practices when you are writing code that may cause this kind of issue, and especially if you are creating a framework or a library.
Make all your concrete classes final by default, because you probably don't want them to be inherited. You can find this behavior as a feature of many languages, such as Kotlin. Besides, if you need to extend it, you can always remove the final keyword. In this way the absence of final on a class can be interpreted as a warning to not rely on specific functionality for other methods on this that are not private and/or final.
For classes that cannot be marked as final, make as many methods as possible final to ensure they're not modified by subclasses. Additionally, do not expose methods that are not meant to be overridden—prefer private over protected. Assume that any method not private and/or final will be overridden and ensure that your superclass code will still work.
Try to not use an inheritance ("Bar is a Foo") relationship. Instead use a helper ("Bar uses a Foo") relationship between your classes. Use interfaces rather than abstract classes to ensure that classes using this helper have a uniform interface.
Remember that almost* every extends can be replaced by implements. This is true event when you want to have a default implementation; an example of such a conversion is shown below:
Old Code:
class Superclass {
void foo() {
// implementation
}
void bar() {
// implementation
}
}
class Subclass extends Superclass {
// don't override `foo`
// override `bar`
#Override
void bar() {
// new implementation
}
}
New Code:
// Replace the superclass with an interface.
public interface IClass {
void foo();
void bar();
}
// Put any implementation in another, final class.
final class Superclass implements IClass {
public void foo() {
// implementation for superclass
}
public void bar() {
// implementation for superclass
}
}
// Instead of `extend`ing the superclass and overriding methods,
// use an instance of the implementation class as a helper.
// Naturally, the subclass can also forgo the helper and
// implement all the methods for itself.
class Subclass implements IClass {
private Superclass helper = new Superclass();
// Don't override `foo`.
public void foo() {
this.helper.foo();
}
// Override `bar`.
public void bar() {
// Don't call helper; equivalent of an override.
// Or, do call helper, but the helper's methods are
// guaranteed to be its own rather than possibly
// being overridden by yours.
}
}
The advantage of this is that the methods of the superclass are able to be sure they are working with one another, but at the same time you can override methods in your subclass.
*If you actually wanted the superclass to use your overridden method you are out of luck using this approach unless you also want to reimplement all of those methods on the "subclass". That said, the superclass calling the subclass can be confusing so it may be good to reevaluate that type of usage, its incompatibility with this approach notwithstanding.

Related

Using default keyword in interface correctly

I have a co worker who need a method to be available to two classes.
He decided to create a new interface to be implemented by those classes.
The interface has one method
default doThis(String parameter)
It does not have any other interface methods, there is no indication that other methods would be added to this interface.
I feel this is an incorrect usage of the interface and it should be done in a different way. I.e perhaps a class which has the method allowing other classes to consume this by using the object.
Does anyone with experience on this have any opinions to share?
I can update with more clarification based on your comments.
Update:
Here is the code and the question remains:
is this a valid use of the default method or should this common logic have been done in another way like a Utilities class which does the saving to preferences ?
Interface:
public interface LogInCookie {
default void mapCookiesToPreferences(String cookie) {
if (cookie.contains(MiscConstants.HEADER_KEY_REFRESH)) {
String refreshToken = cookie.replace(MiscConstants.HEADER_KEY_REFRESH, StringUtils.EMPTY);
SharedPrefUtils.addPreference(SharedPrefConstants.REFRESH_TOKEN, refreshToken);
}
}
}
public class HDAccountActivity extends AbstractActivity implements LogInCookie {
private void mapCookies(List<String> mValue) {
LogInCookie.super.mapCookiesToPreferences(mValue); //ekh!
}
}
public class BaseSplashPage extends AppCompatActivity implements DialogClickedCallBack, LogInCookie {
//method which uses this
private void mapCookiesToPreferences(List<String> headers) {
int firstItemInHeader = 0;
for (String header : headers) {
String mValue = header.substring(firstItemInHeader,header.indexOf(MiscConstants.SEMICOLON));
LogInCookie.super.mapCookiesToPreferences(mValue); //ekh!
}
}
}
A default method in an interface, which doesn’t define other methods, can’t do much useful things with the instance of the implementing class. It can only use methods inherited from java.lang.Object, which are unlikely to carry semantics associated with the interface.
If the code doesn’t use instance methods on this at all, in other words, is entirely independent from the this instance, you should make it static, change the containing class to a non-instantiable class type, i.e.
final class SomeUtilClass {
static void doThis(String parameter) {
// ...
}
private SomeUtilClass() {} //no instances
}
and use import static packageof.SomeUtilClass.doThis; in the classes using this method.
That way, all these classes can invoke the method like doThis(…) without a qualifying type name, without needing a misleading type hierarchy.
When the method actually uses the this instance, which, as said, can only be in terms of methods inherited from java.lang.Object, the type inheritance might be justified. Since this is rather unlikely, you might still consider the type hierarchy to be misleading and rewrite the code to
final class SomeUtilClass {
static void doThis(Object firstParameter, String parameter) {
// ...
}
private SomeUtilClass() {} //no instances
}
using firstParameter instead of this, which can be invoke like doThis(this, …).
Ideally you would put that method doThis() in an abstract class that both classes extend. However if you need to achieve multiple inheritance then using an interface here is fine.
A class with a static method doThis() that you can call staticly would also work.
It all depends on how you have your project organized imo.
In java 8 , default keyword in interface was introduced for those cases where if any set of apis had long inheritance hierarchy and we wanted to introduce a method that should be available in all of the lower lying classes.
So for ex. in Java 8 stream() method was introduced in the Collection interface as a default method and it ended up being available in all of the underlying classes.
As far as your case in considered , if I go by your words then if yours is a new development then you should be using interface -> abstract class -> actual implementing class.
Only if yours was an older development setup and you already had classes implementing from an interface , that could have been an ideal scenario for using default method in your interface.
A default method in an interface
*)can have a default implementation
*)which can overridden by the implementing class
yes its a correct usage since JAVA8.
we can have default method in an interface as well as a abstract method

Why does Java not allow multiple inheritance but does allow conforming to multiple interfaces with default implementations

I am not asking this -> Why is there no multiple inheritance in Java, but implementing multiple interfaces is allowed?
In Java, multiple inheritance isn't allowed, but, after Java 8, Interfaces can have default methods (can implement methods itself), just like abstract classes. Within this context, it multiple inheritance should also be allowed.
interface TestInterface
{
// abstract method
public void square(int a);
// default method
default void show()
{
System.out.println("Default Method Executed");
}
}
Things are not so simple.
If a class implements multiple interfaces that defines default methods with the same signature the compiler will force you to override this method for the class.
For example with these two interfaces :
public interface Foo {
default void doThat() {
// ...
}
}
public interface Bar {
default void doThat() {
// ...
}
}
It will not compile :
public class FooBar implements Foo, Bar{
}
You should define/override the method to remove the ambiguity.
You could for example delegate to the Bar implementation such as :
public class FooBar implements Foo, Bar{
#Override
public void doThat() {
Bar.super.doThat();
}
}
or delegate to the Foo implementation such as : :
public class FooBar implements Foo, Bar {
#Override
public void doThat() {
Foo.super.doThat();
}
}
or still define another behavior :
public class FooBar implements Foo, Bar {
#Override
public void doThat() {
// ...
}
}
That constraint shows that Java doesn't allow multiple inheritancy even for interface default methods.
I think that we cannot apply the same logic for multiple inheritances because multiples issues could occur which the main are :
overriding/removing the ambiguity for a method in both inherited classes could introduce side effects and change the overall behavior of the inherited classes if they rely on this method internally. With default interfaces this risk is also around but it should be much less rare since default methods are not designed to introduce complex processings such as multiple internal invocations inside the class or to be stateful (indeed interfaces cannot host instance field).
how to inherit multiple fields ? And even if the language allowed it you would have exactly the same issue as this previously quoted : side effect in the behavior of the inherited class : a int foo field defined in a A and B class that you want to subclass doesn't have the same meaning and intention.
The language designers already thought about that, so these things are enforced by the compiler. So if you define:
interface First {
default void go() {
}
}
interface Second {
default void go() {
}
}
And you implement a class for both interfaces:
static class Impl implements First, Second {
}
you will get a compilation error; and you would need to override go to not create the ambiguity around it.
But you could be thinking that you can trick the compiler here, by doing:
interface First {
public default void go() {
}
}
static abstract class Second {
abstract void go();
}
static class Impl extends Second implements First {
}
You could think that First::go already provides an implementation for Second::go and it should be fine. This is too taken care of, thus this does not compile either.
JLS 9.4.1.3 : Similarly, when an abstract and a default method with matching signatures are inherited, we produce an error. In this case, it would be possible to give priority to one or the other - perhaps we would assume that the default method provides a reasonable implementation for the abstract method, too. But this is risky, since other than the coincidental name and signature, we have no reason to believe that the default method behaves consistently with the abstract method's contract - the default method may not have even existed when the subinterface was originally developed. It is safer in this situation to ask the user to actively assert that the default implementation is appropriate (via an overriding declaration).
The last point I would bring in, to solidify that multiple inheritance is not allowed even with new additions in java, is that static methods from interfaces are not inherited. static methods are inherited by default:
static class Bug {
static void printIt() {
System.out.println("Bug...");
}
}
static class Spectre extends Bug {
static void test() {
printIt(); // this will work just fine
}
}
But if we change that for an interface (and you can implement multiple interfaces, unlike classes):
interface Bug {
static void printIt() {
System.out.println("Bug...");
}
}
static class Spectre implements Bug {
static void test() {
printIt(); // this will not compile
}
}
Now, this is prohibited by the compiler and JLS too:
JLS 8.4.8 : A class does not inherit static methods from its superinterfaces.
Java doesn't allow multiple inheritance for fields. This would be difficult to support in the JVM as you can only have references to the start of an object where the header is, not arbitrary memory locations.
In Oracle/Openjdk, objects have a header followed by the fields of the most super class, then the next most super class, etc. It would be a significant change to allow the fields of a class to appear at different offsets relative to the header of an object for different subclasses. Most likely object references would have to become a reference to the object header and a reference to the fields to support this.
default methods in interfaces pose a problem that :
If both of the implemented interfaces define a default method with
same method signature, then the implementation class does not know
which default method to use.
The implementation class should define explicitly specify which default method to use or define it's own one.
Thus default methods in Java-8 do not facilitate multiple inheritance. The main motivation behind default methods is that if at some point we need to add a method to an existing interface, we can add a method without changing the existing implementation classes. In this way, the interface is still compatible with older versions. However, we should remember the motivation of using Default Methods and should keep the separation of interface and implementation.
The main issues with multiple inheritance are ordering (for overriding and calls to super), fields and constructors; interfaces don't have fields or constructors, so they don't cause problems.
If you look at other languages they usually fall in two broad categories:
Languages with multiple inheritance plus a few features to disambiguate special cases: virtual inheritance [C++], direct calls to all superconstructors in the most-derived class [C++], linearization of superclasses [Python], complex rules for super [Python], etc.
Languages with a differente concept, usually called interfaces, traits, mixins, modules, etc. that impose some limitations such as: no constructors [Java] or no constructors with parameters [Scala until very recently], no mutable fields [Java], specific rules for overriding (e.g. mixins take precedence over base classes [Ruby] so you can include them when you need a bunch of utility methods), etc. Java has become a language like these.
Why just by disallowing fields and constructors you solve many issues related to multiple inheritance?
You can't have duplicated fields in duplicated base classes.
The main class hierarchy is still linear.
You can't construct your base objects the wrong way.
Imagine if Object had public/protected fields and all subclasses had constructors setting those fields. When you inherit from more than one class (all of them derived from Object), which one gets to set the fields? The last class? They become siblings in the hierarchy, so they know nothing about each other. Should you have multiple copies of Object to avoid this? Would all classes interoperate correctly?
Remember that fields in Java are not virtual (overridable), they are simply data storage.
You could make a language where fields behave like methods and could be overridden (the actual storage would be always private), but that would be a much bigger change and problably wouldn't be called Java anymore.
Interfaces can't be instantiated by themselves.
You should always combine them with a concrete class. That eliminates the need for constructors and makes the programmer's intent clearer too (that is, what is meant to be a concrete class and what's an accessory interface/mixin). This also provides a well-defined place to solve all ambiguities: the concrete class.
That is mostly related to "diamonds problem" i think. Right now if you implement multiple interfaces with the same method, compiler forces you to override method the one you want to implement, because it don't know which on to use. I guess Java creators wanted to remove this problem back when interfaces couldn't use default methods. Now they came up with idea, that is good to be able to have methods with implementation in interfaces, as you can still use those as functional interfaces in streams / lambda expressions and utilize their default methods in processing. You cannot do that with classes but diamond problem still exist there. That is my guess :)
class A{
void m1(){
System.out.println("m1-A");
}
}
class B{
void m1(){
System.out.println("m1-B");
}
}
class C extends A, B{ // this will give an error
// inheritance means making all variables and/or methods available to the child class, here child class will get confused as which m1() method to inherit, hence an error
}
JAVA DOES SUPPORT MULTIPLE INHERITANCE.
If you make a OVERALL COMPARISON OF THE PROGRAMMING LANGUAGE,JAVA,THEN YOU COME TO KNOW THAT I AM TRUE.
Java's topclass or the root class in the Ancestor Hierarchy is the Object class.
This class is a Superclass of all other classes. Hence, each class in Java that we declare or is predefined in the API itself inherits this Object class.
Moreover, Java provides us to inherit one more class of our choice.
Hence, we can say that we are performing INTERLOCKED BUT MULTIPLE INHERITANCE.
2ND Way
Java supports Multiple Inheritance of Interfaces. So you can use as many interface implementations you want. But note, implementing an interface does not define IS A relationship as in case of Inheritance of Classes is possible.

why Java 8 interface static methods cannot override Object class methods [duplicate]

I'm confused why the following is not allowed:
public interface MyInterface {
MyInterface getInstance(String name);
}
public class MyImplementation implements MyInterface {
public MyImplementation(String name) {
}
#Override
public static MyInterface getInstance(String name) { // static is not allowed here
return new MyImplementation(name)
}
}
I understand why a method in the interface cannot be static, but why can't the overriding method be?
I want all classes to implement the getInstance(String name) method, but I'm currently limited to only being able to call the method if the object has already been instantiated which kind of defeats the purpose...
*update:* Thanks for the answers, I understand it better now. Basically I shouldn't be trying to make a utility class (or a factory class for that matter) implement an interface (or at least, not in this way)...
Invoking static methods in Java requires you to specify the exact type. It is not possible to invoke static methods polymorphically, eliminating the need for #Override.
Please note that this approach is not universal across all languages: for example, you can override class methods in Objective-C, and Apple's cocoa frameworks make good use of this mechanism to customize their "factory" classes. However, in Java, C++, and C# class methods do not support polymorphic behavior.
Theoretically, Java designers could have let you provide interface method implementations through static methods in case an implementation does not need to access the state from the instance. But the same behavior is simple to achieve with a trivial wrapper:
public class MyImplementation implements MyInterface {
public MyImplementation(String name) {
}
#Override
public MyInterface getInstance() { // static is not allowed here
return getInstanceImpl();
}
public static getInstanceImpl() {
return new MyImplementation(name)
}
}
Java compiler could have done the same thing on your behalf, but seeing a static method implement an instance method is both unusual and confusing, so my guess is that Java designers decided against providing this "piece of magic".
Static methods cannot be subject to polymorphic behavior. That would not make much sense. Image this use case, assuming what you want would be possible:
public void foo(MyInterface i) {
i.getInstance("abc");
}
now I want to call this method with an implementation of MyInterface (class A), but since I cannot pass the class itself, I need to pass an object:
A a = new A();
foo(a);
now inside foo the static override of getInstance is called on the instance of class A. So now I am stuck with creating an object just to call a static method.
My point is that you would still be constrained to create an object in most use cases of polymorphism since in your original interface the method was an instance method.
because implementing an interface makes the implementor the type of the interface. That means instances need to have the methods defined by the type, not the class of the instances.
To put it another way,
public void mymethod
and
public static void mymethod
are NOT the same method declaration. They are completely distinct. If mymethod is defined on an interface, having the second definition simply does not satisfy implementing the interface.
The answer comes down to what it means to implement an interface. When a class implements an interface, that is a promise that every instance of the class will respond to every method in the interface. When you implement the method as static, you make it possible to call the method without an instance of the class - but that doesn't fulfill the inheritance implementation's promise that the method will be callable on every instance of the class.

java - unique difference between abstract class and concrete class

I know few differences between abstract class and concrete class. I know that you can't create an instance with abstract class unlike concrete class, abstract class can have 'abstract' methods.
But i have an example like the following. A lot of times, we see the following examples at work. I will just skip some common methods that can be defined in the Parent class.
public abstract class Parent {
public void init() {
doInit();
}
public abstract void doInit();
}
public class Child extends Parent {
public void doInit() {
// implementation
}
}
I think that we can do the same thing with a concrete class like the following.
public class Parent {
public void init() {
doInit();
}
public void doInit() {
// Empty
}
}
I am curious to see if there is any unique situation that we have to use abstract class. Is there any significant difference during runtime with the above example?
Thank you.
The reason to use abstract class in this situation is to force everyone inheriting your base class to override the abstract doInit method. Without the class and the method being abstract, they may forget to do so, and the compiler would not catch them.
In addition to this pragmatic purpose, abstract classes provide a powerful way to communicate your design idea to the readers of your code. An abstract class tells the reader that the methods inside provide some common implementation for a group of related classes, rather than implementing a single concept that you are modeling. Very often communicating your intent to your readers is as important as it is to write correct code, because otherwise they might break something while maintaining your code.
It is customary in Java to call abstract classes Abstract...; in your example that would be AbstractParent.
Of course you can do it that way, but it all depends on the right business logic.There might arise a situation where you'd want to enforce a policy on people extending your code.
For example, I write an Employee class and you extend my class for writing a ProjectManager class. But suppose the business does not allow direct instantiation of Employee (like I said, just an example). So I declare my Employee class as abstract, thereby enforcing upon all extenders (read:you) of my class the rule that they can't instantiate Employee directly. (It will happen indirectly through the inheritance chain, of course, i.e. parent objects are created before child objects.)
Used properly, a person at place A controls how another person at place B will code.
A concrete class is one which has implementation (code inside) for all the methods. It does not matter whether it is derived from some other class.
public abstract class IAmAbstract{
public void writeMe(){
System.out.println("I am done with writing");
}
}
public class IAmConcrete extends IAmAbstract{
public void writeMe(){
System.out.println("I am still writing");
}
}
Abstract classes have a variety of useful properties in use with software design.
Other than the obvious differences, such as being unable to be instantiated and being able to hold abstract methods. They are useful for defining common, yet overridable, functions, holding static methods that deal with it's children in a logical manner.
My favorite is the abstract factory pattern though.
By making a factory that is the parent of all the classes it may create, it can force functionality required for creation, this actually causes an odd artefact where technically tighter-coupled code is actually easier to maintain.

Java: Make a method abstract for each extending class

Is there any keyword or design pattern for doing this?
Please check the update
public abstract class Root
{
public abstract void foo();
}
public abstract class SubClass extends Root
{
public void foo()
{
// Do something
//---------------- Update -------------------//
// This method contains important code
// that is needed when I'm using a instance
// of SubClass and it is no instance of any
// other class extending SubClass
}
}
public class SubberClass extends SubClass
{
// Here is it not necessary to override foo()
// So is there a way to make this necessary?
// A way to obligate the developer make again the override
}
Thanks
If you are doing this, then you are probably abusing inheritance; inheritance, contrary to popular myth, is not intended for making custom hooks/handlers, but rather to enable alternative implementations.
If you want your user to provide some sort of function/hook/callback, then you should define an interface that provides just those methods that you need your user to define. Then you should require the user to pass in an instance of that interface to your object's constructor or passed into the function that needs it.
Aggregation, delegation, and composition are frequently better and safer design patterns than inheritance; forcing other users to inherit from your class, is incredibly risky, as it provides the user with many opportunities to violate the contract of your class or to invalidate the invariant of your base class.
If every class subclassing SubClass has to override foo() then why provide an implementation at all in SubClass? You can simply remove the method definition from SubClass and then all subclasses will be forced to provide an implementation.
If you really want to, you can re-declare foo as abstract.
public abstract class SubberClass extends SubClass
{
public abstract void foo();
}
Instead of overriding foo() in SubClass, create a new method fooImpl() and leave foo() abstract. This way, all classes must implement foo() but you can simply implement it by calling fooImpl() if that is already enough.
Yeah it is not necessary to override foo() in SubberClass.
You can't have it both ways. You can't provide a method with a default implementation AND require child classes override it. Instead of declaring the method as abstract in Root, you could define an interface (IFoo) with the method declared and then provide an abstract class that implements the interface. That would still require a concrete child class but would not require a method override.
Most of the time you see this type of pattern, an interface is used to define a set of methods and an abstract base class provides some default implementations for some but not all methods from the interface. This requires the concrete child class to provide code for the remaining methods and the option to override the default behaviors.
In any case, you can't provide a default behavior for a single method and require child classes to override that same method.

Categories

Resources