Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.example.foo;
- import static java.lang.String.format;
- import static java.util.Arrays.asList;
- import static java.util.Objects.requireNonNull;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- import java.util.List;
- /**
- * This is to demponstrate how to implement {@link Comparable} in a decorator class.
- * <p>
- * Blog post: https://humanoidreadable.wordpress.com/2014/12/15/decorator-implementing-comparable/
- * <p>
- * {@link IFoo}: The abstract model.<br>
- * {@link Foo}: Some basic implementation.<br>
- * {@link IFoo}: The decorator.<br>
- * {@link Proxy}: Proxy (reflection).
- *
- * @author Claude Martin
- *
- */
- public class SomeClass {
- public static void main(String[] args) throws Exception {
- // Classic decoration:
- IFoo foo0 = new Foo(42);
- IFoo foo1 = new FooDecorator(foo0);
- IFoo foo2 = new Foo(1337);
- IFoo foo3 = new FooDecorator(foo2);
- // Decorated decorator: [[1337]]
- IFoo foo4 = new FooDecorator(foo3);
- // Decoration by Proxy:
- IFoo.Handler handler = SomeClass::handle;
- IFoo foo5 = IFoo.decorate(foo0, handler);
- IFoo foo6 = IFoo.decorate(foo2, handler);
- IFoo foo7 = IFoo.decorate(foo3, handler);
- IFoo foo8 = IFoo.decorate(foo7, handler);
- // foo9->foo7->foo3->foo2: [{[1337]}]
- IFoo foo9 = new FooDecorator(foo7);
- List<IFoo> foos = asList(foo0, foo1, foo2, foo3, foo4, foo5, foo6, foo7, foo8, foo9);
- for (IFoo a : foos) {
- for (IFoo b : foos) {
- int i = a.compareTo(b);
- System.out.println(format("%s.compareTo(%s) = %d", a, b, i));
- boolean e = a.equals(b);
- System.out.println(format("%s.equals(%s) = %s", a, b, e));
- }
- }
- }
- /**
- * Wraps toString in "{?}".
- *
- * @see IFoo#decorate(IFoo, com.example.foo.SomeClass.IFoo.Handler)
- */
- private static Object handle(IFoo foo, Method method, Object[] arguments) throws Throwable {
- // decoration:
- if (method.getName().equals("toString"))
- return "{" + foo.toString() + "}";
- // delegation:
- return method.invoke(foo, arguments);
- }
- /**
- * A decorator of an instance of IFoo.
- *
- * This decorates the toString method by wrapping the value in "[?]".
- */
- public static class FooDecorator implements IFoo {
- private final IFoo field;
- public FooDecorator(IFoo field) {
- super();
- this.field = requireNonNull(field, "field");
- }
- @Override
- public int hashCode() {
- return this.field.hashCode();
- }
- @Override
- public boolean equals(Object other) {
- return this == other || this.field.equals(other);
- }
- @Override
- public int compareTo(IFoo other) {
- return this.field.compareTo(other);
- }
- @Override
- public int getValue() {
- return this.field.getValue();
- }
- @Override
- public String toString() {
- return "[" + this.field.toString() + "]";
- }
- }
- /**
- * Implementation of IFoo.
- *
- * I recommend to make this class final or even immutable.
- */
- public/* final */static class Foo implements IFoo {
- private final int value;
- public Foo(int value) {
- this.value = value;
- }
- @Override
- public int compareTo(IFoo other) {
- return Integer.compare(this.getValue(), other.getValue());
- }
- @Override
- public int getValue() {
- return this.value;
- }
- @Override
- public String toString() {
- return Integer.toString(this.value);
- }
- @Override
- public int hashCode() {
- return this.value;
- }
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (!(obj instanceof IFoo))
- return false;
- IFoo other = (IFoo) obj;
- if (this.getValue() != other.getValue())
- return false;
- return true;
- }
- @SuppressWarnings("static-method")
- public boolean canEqual(Object other) {
- return (other instanceof Foo);
- }
- }
- /**
- * The interface which models the abstract idea of the "Foo".
- */
- interface IFoo extends Comparable<IFoo> {
- public int getValue();
- /**
- * TODO: This should explain in great detail when two instances of IFoo are equal. In this case
- * it would be equal if both have the same value. But what if some implementation has more
- * fields? cf: http://www.artima.com/lejava/articles/equality.html
- */
- @Override
- public boolean equals(Object obj);
- /**
- * TODO: Any type with a special definition of {@link #equals(Object)} should also specify how a
- * hashCode must be calculated. In this case it's just the value.
- */
- @Override
- public int hashCode();
- /**
- * TODO: This should explain in great detail how two instances of IFoo are to be compared. In
- * this case it compares the values. But what if some implementation has more fields?
- */
- @Override
- public int compareTo(IFoo o);
- /** Decorates an instance of IFoo using a given handler. */
- public static IFoo decorate(final IFoo foo, final Handler handler) {
- requireNonNull(foo, "foo");
- requireNonNull(handler, "handler");
- return (IFoo) Proxy.newProxyInstance(IFoo.class.getClassLoader(), new Class[] { IFoo.class },
- (proxy, method, args) -> {
- return handler.invoke(foo, method, args);
- });
- }
- /** Handler of method calls to a decorated instance if IFoo. */
- @FunctionalInterface
- public static interface Handler {
- public Object invoke(IFoo foo, Method method, Object[] args) throws Throwable;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement