The skeletal implementation pattern is a software design pattern
consisting of defining an abstract class that provides a partial interface implementation. However, since Java allows only single class inheritance, if implementers decide to extend a skeletal implementation, they will not be allowed to extend any other class. Also, discovering the skeletal implementation may require a global analysis. Java 8 enhanced interfaces alleviate these problems by allowing interfaces to contain (default) method implementations, which implementers inherit. Java classes are then free to extend a different class, and a separate abstract class is no longer needed; developers considering implementing an interface need only examine the interface itself. We argue that both these benefits improve software modularity, and discuss our ongoing work in developing an automated refactoring tool that would assist developers in taking advantage of the enhanced interface feature for their legacy Java software.
2. New Features in Java 8
Largest change was in ~2005 with Java 5.
10 years later, Java 8 is packed with new features.
Java 9 is on the horizon (Project Jigsaw, i.e., "modular Java", etc.)
Our focus is Java 8 enhanced interfaces that allow defaultmethods.
3. Java Interfaces
A list of publicmethod declarations (no bodies) that
concrete implementers (classes) must de ne.
4. The Java Interface Type
Cannot be instantiated (abstract).
Cannot contain instance elds.
Can extend other interfaces.
Can contain public static elds and methods (new in Java 8).
Multiple classes can implement an interface and an
interface can be implemented by multiple classes.
5. Example
Listcontains declarations of methods common to all lists.
interfaceList<E>{//...
/**
*Removesalloftheelementsfromthislist(optionaloperation).
*@throwsUnsupportedOperationExceptioniftheclearoperation
*isnotsupportedbythislist.
*/
voidclear();//...
}
MyListis a particular kind of list.
classMyList<E>implementsList<E>{//...
@Override
publicvoidclear(){//notsupported.
thrownewUnsupportedOperationException();
}//...
}
A Listcan refer to MyListinstances in clients.
List<E>list=newMyList<>();
8. Skeletal Implementations
Provide separate abstractclass as a partial interface implementation
[Bloch'08].
Implementers extendthe skeletal implementation instead.
Inherit "default" and/or partial interface method de ntions.
Makes implementing the interface easier.
10. Issues
Flexibility
Java has single class inheritance -> classes cannot extend classes
other than the skeletal implementation (can use delegation instead
[Bloch'08]).
Evolvability
Interface modi cations must be in sync with skeletal
implementions in separate classes.
Modularity
No syntatical path from the interface to its skeletal implementation.
Developers wishing to implement an interface may need a global
analysis to nd corresponding skeletal implementers.
12. Default Methods
Traditionally, interfaces can't have method de nitions (just
declarations).
Default methods supply default implementations of interface
methods.
By default, implementers will receive this implementation if they don't
provide their own.
22. Motivation
Two cases:
1. Complete migration of skeletal implementation to interface.
Makes type hierarchy less complicated.
One less type.
Makes interfaces easier to implement.
No global analysis required to nd skeletal implemention.
Makes interfaces easier to maintain.
No simultaneous modi cations between interface and skeletal
implementation required.
2. Partial migration of skeletal implementation to interface.
Possibly makes interfaces easier to implement.
All implementations may not need to extend the skeletal
implementation.
Possibly makes interfaces easier to maintain.
Possibily less simultaneous modi cations between interface and
skeletal implementation required.
23. Work in Progress
Can eliminate the need for skeletal implementations?
Can we automate this?
1. How do we determine if an interface
implementor is "skeletal?"
2. What is the criteria for an instance method to be
converted to a default method?
3. What if there is a hierarchy of skeletal
implementors, e.g., AbstractCollection,
AbstractList?
4. How do we preserve semantics?
5. What client changes are necessary?
25. Why is this Complicated?
Corresponds to converting and migrating a skeletal (instance) method
implementation to an interface.
From a class To an interface
instancemethod defaultmethod
Can we not simply use a "Pull Up Method" [Fowler'99] refactoring?
Not exactly. The inherent problem is that, unlike
classes, interfaces may extend multiple interfaces. As
such, we now have a kind of multiple inheritance
problem to deal with.
26. Some (perhaps) Obvious
Preconditions
Source instancemethod must not access any instance elds.
Interfaces may not have instance elds.
Can't currently have a defaultmethod in the target interface with
the same signature.
Can't modify target method's visibility.
27. Some Obvious Tasks
Must replace the target method in the interface(add a body to it).
Must add the defaultkeyword.
Must remove any @Overrideannotations (it's top-level now).
If nothing left in abstractclass, remove it?
Need to deal with documentation.
28. Some Not-so-obvious
Preconditions
Suppose we have the following situation:
interfaceI{
voidm();
}
interfaceJ{
voidm();
}
abstractclassAimplementsI,J{
@Override
voidm(){...}
}
Here, Aprovides a partial implementation of I.m(), which also happens
to be declared as part of interface J.
29. Some Not-so-obvious
Preconditions
Now, we convert and migrate A.m()to a default method of I:
interfaceI{
defaultvoidm(){..}//wasvoidm();
}
interfaceJ{
voidm();//staysthesame.
}
abstractclassAimplementsI,J{
//nowempty,was:voidm(){...}
}
We now have a compile-time error in Abecause Aneeds to declare
which m()it inherits.
In general, inheritance hierarchies may be large and complicated.
Other preconditions may also exist (work in progress).