how to create an interface around classes that alr

2019-07-14 04:22发布

问题:

Suppose I already have 2 classes in my code:

class SomeOrder {
  String getOrderId() { return orderId; }
}

class AnotherOrder {
  String getOrderId() { return orderId; }
}

How to create an interface around both these classes which is:

interface Order {
    String getOrderId();
}

Ideally, I would modify the code so that SomOrder implements Order and AnotherOrder implements Order but the catch here is that they belong in a package that I cannot control or edit (i.e. they come from an external jar).

My algorithm currently looks like this:

void sorter(List<SomeOrder> orders) {
    ... <custom sort logic> ...
    someOrder.getOrderId();
}

void sorter(List<AnotherOrder> orders) {
    ... <custom sort logic> ...
    someOrder.getOrderId();
}

With a single interface I can write:

void sorter(List<Order> orders) {
        ... <custom sort logic> ...
        order.getOrderId();
}

回答1:

You can use adapter classes:

class SomeOrderAdapter implements Order {
    private SomeOrder delegate;

    @Override
    public String getOrderId() {
        return delegate.getOrderId();
    }
}

and similar for AnotherOrder.



回答2:

Since your interface is a functional interface, you could define functions that map to this new Order interface my referencing the getOrderId method for each different class:

private Order wrap(SomeOrder obj) {
    return obj::getOrderId;
}

private Order wrap(AnotherOrder obj) {
    return obj::getOrderId;
}

An example calling it:

private void test() {
    List<Order> orders = Arrays.asList(
        wrap(new SomeOrder()),
        wrap(new AnotherOrder())
    );
    sorter(orders);
}


回答3:

Create a Proxy wrapped around the instances implementing the interface you need. The proxy just calls the instance's method with the same parameters.

public class Proxied<T> implements InvocationHandler {
  private final T wrapped;

  public Proxied(T wrapped) {
    this.wrapped = Objects.requireNonNull(wrapped);
  }

  public T getWrapped() {
    return wrapped;
  }

  public <I> Class<I> proxy(Class<I> interfaceClass) {
    @SuppressWarnings("unchecked")
    Class<I> proxyClass = (Class<I>)  Proxy.getProxyClass(getClass().getClassLoader(), interfaceClass);
    return proxyClass;
  }

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    return method.invoke(wrapped, args);
  }
}