With this approach "To enrich an interface using traits, simply define a trait with a small number of abstract methods—the thin part of the trait’s interface—and a potentially large number of concrete methods, all implemented in terms of the abstract methods. Then you can mix the enrichment trait into a class, implement the thin portion of the interface, and end up with a class that has all of the rich interface available."
The following Scala code is an example:
class Point(val x: Int, val y: Int) trait Rectangular { // abstract methods def topLeft: Point def bottomRight: Point def left = topLeft.x def right = bottomRight.x def width = right - left } class Rectangle(val topLeft: Point, val bottomRight: Point) extends Rectangular { // other methods... }With this setup we can write:
val rect : Rectangular = new Rectangle(new Point(1, 1), new Point(10, 10)) println(rect left) //prints 1 println(rect right) //prints 10 println(rect width) //prints 9We will now have a peek and the resulting decompiled .class files and see how this magic looks like from the Java point of view (1). The Point class is unsurprising:
public class Point { private final int x; private final int y; public Point(int x, int y) { this.x = x; this.y = y; } public int x() { return x; } public int y() { return y; } }Things become more interesting with Rectangular. The trait results in two Java classes: Rectangular.java and Rectangular$class.java.
public interface Rectangular { public abstract Point topLeft(); public abstract Point bottomRight(); public abstract int left(); public abstract int right(); public abstract int width(); } public abstract class Rectangular$class { public static int left(Rectangular $this) { return $this.topLeft().x(); } public static int right(Rectangular $this) { return $this.bottomRight().x(); } public static int width(Rectangular $this) { return $this.right() - $this.left(); } public static void $init$(Rectangular rectangular) {} }Effectively the trait is broken up into two parts - an interface part (Rectangular.java) and an implementing class (Rectangular$class.java) which is not related to Rectangular at all and carries the implemented trait methods as static Java methods.
Finally, the Rectangle class looks like this:
public class Rectangle implements Rectangular { private final Point topLeft; private final Point bottomRight; public Rectangle(Point topLeft, Point bottomRight) { this.topLeft = topLeft; this.bottomRight = bottomRight; Rectangular.class.$init$(this); } public Point topLeft() { return topLeft; } public Point bottomRight() { return bottomRight; } // the mixin public int left() { return Rectangular.class.left(this); } public int right() { return Rectangular.class.right(this); } public int width() { return Rectangular.class.width(this); } }where we see that mixin logic is statically delegated to Rectangular.
(1) Compiled with Scala 2.11, decompiled with Jad.
No comments:
Post a Comment