Archive for March 2013
Java 8 and mixin with default methods
I wanted to check out “mixins” in Java 8 or so called default methods in interfaces. So what is default methods in interfaces in Java. Interfaces in JDK 8 can have full method definitions by using the default keyword. Since I am an Scala fanboy I wanted to test the Stackable Trait Pattern. So here goes. First I created an interface called IntQueue with the default methods get and put. I can not extend an abstract class to an interface, so IntQueue must be an interface or else I can not mix it in.
package com.reidarsollid.eight.mixins; import java.util.Queue; public interface IntQueue { Queue getQueue(); default int get() { return getQueue().remove(); } default void put(int x) { getQueue().add(x); } }
So far so good, so then I want to mix in WithDoubling I want to double what comes inn to the put method. I can not call super on an inherited interface but I can call i through the interface like an inner class calling an outer class.
package com.reidarsollid.eight.mixins; public interface WithDoubling extends IntQueue { default void put(int x) { IntQueue.super.put(x * 2); } }
So I wanted to create a BasicIntQueue and mix in the WithDoubling interface. This works as I wanted 🙂
package com.reidarsollid.eight.mixins; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedDeque; public class BasicIntQueue implements IntQueue, WithDoubling { private Queue integerQueue = new ConcurrentLinkedDeque<>(); @Override public Queue getQueue() { return integerQueue; } }
Then I created a WithFilter interface to check if the numbers are above 0.
package com.reidarsollid.eight.mixins; public interface WithFiltering extends IntQueue { default void put(int x) { if (x > 0) IntQueue.super.put(x); } }
Then i mixed in the WithFiltering interface in the BasicIntQueue.
package com.reidarsollid.eight.mixins; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedDeque; public class BasicIntQueue implements IntQueue, WithDoubling, WithFiltering { private Queue integerQueue = new ConcurrentLinkedDeque<>(); @Override public Queue getQueue() { return integerQueue; } }
Thats when the fun stopped, when compiling this I get this compiler error. java: class com.reidarsollid.eight.mixins.BasicIntQueue inherits unrelated defaults for put(int) from types com.reidarsollid.eight.mixins.WithDoubling and com.reidarsollid.eight.mixins.WithFiltering
But then again I can solve this puzzle with decorator pattern So first I create an IntQueue interface.
package com.reidarsollid.eight.decorator; public interface IntQueue { int get(); void put(int x); }
Then I created the IntQueueDecorator
package com.reidarsollid.eight.decorator; public abstract class IntQueueDecorator implements IntQueue { protected final IntQueue intQueueDecorator; public IntQueueDecorator(IntQueue intQueue) { this.intQueueDecorator = intQueue; } public int get() { return intQueueDecorator.get(); } public void put(int element) { intQueueDecorator.put(element); } }
And now I can add on as many decorators as I want. The Doubling decorator.
public class Doubling extends IntQueueDecorator { public Doubling(IntQueue intQueue) { super(intQueue); } @Override public int get() { return super.get(); } @Override public void put(int element) { element = element * 2; super.put(element); } }
The Filtering decorator.
package com.reidarsollid.eight.decorator; public class Filtering extends IntQueueDecorator { public Filtering(IntQueue intQueue) { super(intQueue); } @Override public int get() { return super.get(); } @Override public void put(int element) { if (element >= 0) { super.put(element); } } }
The Increment decorator.
package com.reidarsollid.eight.decorator; public class Increment extends IntQueueDecorator { public Increment(IntQueue intQueue) { super(intQueue); } @Override public int get() { return super.get(); } @Override public void put(int element) { element += 1; super.put(element); } }
And then the test class.
package com.reidarsollid.eight.decorator; import org.junit.Test; import java.util.NoSuchElementException; import static junit.framework.Assert.assertEquals; public class IntQueueDecoratorTest { @Test public void testDecorating() throws Exception { IntQueue intQueue = new BasicIntQueue(); intQueue.put(2); int actualBasic = intQueue.get(); int expectedBasic = 2; assertEquals(expectedBasic, actualBasic); intQueue = new Doubling(intQueue); intQueue.put(2); int actualWithDoubling = intQueue.get(); int expectedWithDoubling = 4; assertEquals(expectedWithDoubling, actualWithDoubling); intQueue = new Increment(intQueue); intQueue.put(2); int actualWithDoublingAndIncrement = intQueue.get(); int expectedlWithDoublingAndIncrement = 6; assertEquals(expectedlWithDoublingAndIncrement, actualWithDoublingAndIncrement); } @Test(expected = NoSuchElementException.class) public void testDecoratingWithFilter() { IntQueue intQueue = new Filtering(new Doubling(new Increment(new BasicIntQueue()))); intQueue.put(-1); int actual = intQueue.get(); } }
And we have a green deck. Using decorator pattern adds a little more code, but is easy to use and is readable.