как создать интерфейс вокруг классов, которые уже существуют, но не могут быть изменены в java

Предположим, у меня уже есть 2 класса в моем коде:

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

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

Как создать интерфейс вокруг обоих этих классов, который:

interface Order {
    String getOrderId();
}

В идеале я бы изменил код так, чтобы SomOrder implements Order и AnotherOrder implements Order, но загвоздка здесь в том, что они принадлежат пакету, который я не могу контролировать или редактировать (т. е. они поступают из внешнего jar-файла).

Мой алгоритм на данный момент выглядит так:

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

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

С одним интерфейсом я могу написать:

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

person cafed00d    schedule 20.04.2018    source источник


Ответы (3)


Вы можете использовать классы адаптеров:

class SomeOrderAdapter implements Order {
    private SomeOrder delegate;

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

и аналогично для AnotherOrder.

person Izruo    schedule 20.04.2018

Поскольку ваш интерфейс является функциональным интерфейсом, вы можете определить функции, которые сопоставляются с этим новым интерфейсом Order, ссылаясь на метод getOrderId для каждого другого класса:

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

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

Пример вызова:

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

Создайте Proxy, обернутый вокруг экземпляров, реализующих нужный вам интерфейс. Прокси просто вызывает метод экземпляра с теми же параметрами.

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);
  }
}
person M. le Rutte    schedule 20.04.2018