This is the continuation of my recent article about frameworks where I showed the problems when trying to reuse the three lines of Swap code with different types of containers.
In this Blog, Swap
will be rewritten to become a real framework with abstraction and code-reusage.
Here comes an abstract Swap that will work for any type of Java container. This base class is abstract
because it makes no sense to use it standalone. It defines the responsibilities of the outer world using an inner interface Container
. Every sub-class needs to implement that interface to be able to reuse Swap. There will be a sub-class per container type, like array, list, linked set.
1 | public abstract class Swap<T> |
The Container
interface requires get()
to retrieve an element at a specified index, set()
to put an element to a specified index, size()
to assert given indexes, and it also demands close()
to give problematic containers like LinkedSet
a chance to reorganize completely.
The method performSwap()
is there to be called by sub-classes, not to be overridden, thus it is final
. It provides nice assertions that are done here once-and-only-once. Then it performs the famous three swap statements. Finally it calls close()
on the container interface.
Now let's see if we can derive swaps for all container types from this with acceptable effort.
1 | public class SwapInArray<T> extends Swap<T> |
The ArrayContainer
implementation adapts an array to be a Swap.Container
. Accessing indexes is easy, size also, close is not needed. All this class does is wrapping the given array into an ArrayContainer
and call super.performSwap()
.
1 | import java.util.List; |
The ListContainer
implementation was also very easy to implement. Nearly the same as array, but using get()
and set()
methods. You can see at a glance that there are no errors in that code.
1 | import java.util.ArrayList; |
Here we have the problematic LinkedHashSet
that does not support access to indexes, it just provides iteration. But all the loops and conditions from its recent implementation are gone, replaced by a backing ArrayList
that performs the index access. The ArrayList
constructor receiving the Set
adds all elements of the set, in their iteration-order. This implementation can not work without the close()
call, because it must clear and rebuild the entire collection after swapping. But it does this elegantly by looping the backing list.
Mind that this solution is safe just for one swap. When the Set
would be changed, the backing list would be out-of-date.
To close the swap story, here is some code that you can use to test above classes.
1 | import java.util.ArrayList; |
This outputs:
Before array swap: [0, 1]
After array swap: [1, 0]
Before list swap: [A, B, C, D, E]
After list swap: [A, D, C, B, E]
Before linkedSet swap: [1.0, 100.0, 10000.0]
After linkedSet swap: [1.0, 10000.0, 100.0]
Defining the responsibilities of the outer world as an inner interface or abstract class is a really useful technique. That way the responsibilities are tightly coupled to the class. Any implementation is then free to fulfill them in its own way.
None of the shown classes contains long and hacky methods with complicated loops and conditions. Thus they will contain no mistakes. I call this a clean solution, easy to read and simple to verify.
So, I was able to create a Swap
framework with real abstraction and reusage. But there is more to frameworks, because not everything can be done so simply. Frameworks also provide access to the sometimes complex interactions between classes.
My next example framework will contain several classes playing together. It will demonstrate the importance of a fundamental framework technique called Factory Method. There is no real framework without this pattern, because the object of one class allocates objects of other classes, and you want to determine those classes by overrides. This is possible only by encapsulating the new
operator into a protected
factory method.
You guessed right, I will do this in my next Blog article about frameworks as seen by Java (end titles music playing :-).
ɔ⃝ Fritz Ritzberger, 2016-11-21