Вопрос-ответ

Java - Method name collision in interface implementation

Java - коллизия имен методов в реализации интерфейса

Если у меня есть два интерфейса , оба совершенно разные по своему назначению , но с одинаковой сигнатурой метода , как мне заставить класс реализовать оба, не будучи вынужденным писать единый метод, который служит для обоих интерфейсов , и писать некоторую запутанную логику в реализации метода, которая проверяет, для какого типа объекта выполняется вызов, и вызывает соответствующий код?

В C # это преодолевается тем, что называется явной реализацией интерфейса. Есть ли какой-либо эквивалентный способ в Java?

Переведено автоматически
Ответ 1

Нет, в Java нет способа реализовать один и тот же метод двумя разными способами в одном классе.

Это может привести ко многим запутанным ситуациям, именно поэтому Java запретила это.

interface ISomething {
void doSomething();
}

interface ISomething2 {
void doSomething();
}

class Impl implements ISomething, ISomething2 {
void doSomething() {} // There can only be one implementation of this method.
}

Что вы можете сделать, так это составить класс из двух классов, каждый из которых реализует свой интерфейс. Тогда этот один класс будет вести себя как оба интерфейса.

class CompositeClass {
ISomething class1;
ISomething2 class2;
void doSomething1(){class1.doSomething();}
void doSomething2(){class2.doSomething();}
}
Ответ 2

В Java нет реального способа решить эту проблему. Вы могли бы использовать внутренние классы в качестве обходного пути:

interface Alfa { void m(); }
interface Beta { void m(); }
class AlfaBeta implements Alfa {
private int value;
public void m() { ++value; } // Alfa.m()
public Beta asBeta() {
return new Beta(){
public void m() { --value; } // Beta.m()
};
}
}

Хотя это не позволяет выполнять приведения из AlfaBeta в Beta, понижающие преобразования, как правило, являются злом, и если можно ожидать, что у Alfa экземпляра часто тоже есть Beta аспект, и по какой-то причине (обычно оптимизация - единственная уважительная причина) вы хотите иметь возможность преобразовать его в Beta, вы могли бы создать подинтерфейс Alfa с Beta asBeta() в нем.

Ответ 3

Если вы сталкиваетесь с этой проблемой, это, скорее всего, потому, что вы используете наследование там, где вы должны использовать делегирование. Если вам нужно предоставить два разных, хотя и похожих интерфейса для одной и той же базовой модели данных, то вам следует использовать view, чтобы дешево предоставить доступ к данным с использованием какого-либо другого интерфейса.

Чтобы привести конкретный пример для последнего случая, предположим, вы хотите реализовать оба Collection и MyCollection (которые не наследуются от Collection и имеют несовместимый интерфейс). Вы могли бы предоставить функции Collection getCollectionView() и MyCollection getMyCollectionView(), которые обеспечивают облегченную реализацию Collection и MyCollection, используя те же базовые данные.

В первом случае ... предположим, вам действительно нужен массив целых чисел и массив строк. Вместо наследования от обоих List<Integer> и List<String>, вы должны иметь один элемент типа List<Integer> и другой элемент типа List<String> и ссылаться на эти элементы, а не пытаться наследовать от обоих. Даже если вам нужен был только список целых чисел, в этом случае лучше использовать композицию / делегирование вместо наследования.

Ответ 4

Единственное решение, которое пришло мне в голову, - это использовать объекты referece для того, который вы хотите внедрить в интерфейсы muliple.

например: предположим, у вас есть 2 интерфейса для реализации

public interface Framework1Interface {

void method(Object o);
}

и

public interface Framework2Interface {
void method(Object o);
}

вы можете вложить их в два объекта Facador:

public class Facador1 implements Framework1Interface {

private final ObjectToUse reference;

public static Framework1Interface Create(ObjectToUse ref) {
return new Facador1(ref);
}

private Facador1(ObjectToUse refObject) {
this.reference = refObject;
}

@Override
public boolean equals(Object obj) {
if (obj instanceof Framework1Interface) {
return this == obj;
} else if (obj instanceof ObjectToUse) {
return reference == obj;
}
return super.equals(obj);
}

@Override
public void method(Object o) {
reference.methodForFrameWork1(o);
}
}

и

public class Facador2 implements Framework2Interface {

private final ObjectToUse reference;

public static Framework2Interface Create(ObjectToUse ref) {
return new Facador2(ref);
}

private Facador2(ObjectToUse refObject) {
this.reference = refObject;
}

@Override
public boolean equals(Object obj) {
if (obj instanceof Framework2Interface) {
return this == obj;
} else if (obj instanceof ObjectToUse) {
return reference == obj;
}
return super.equals(obj);
}

@Override
public void method(Object o) {
reference.methodForFrameWork2(o);
}
}

В конце концов, класс, который вы хотели, должен быть чем-то вроде

public class ObjectToUse {

private Framework1Interface facFramework1Interface;
private Framework2Interface facFramework2Interface;

public ObjectToUse() {
}

public Framework1Interface getAsFramework1Interface() {
if (facFramework1Interface == null) {
facFramework1Interface = Facador1.Create(this);
}
return facFramework1Interface;
}

public Framework2Interface getAsFramework2Interface() {
if (facFramework2Interface == null) {
facFramework2Interface = Facador2.Create(this);
}
return facFramework2Interface;
}

public void methodForFrameWork1(Object o) {
}

public void methodForFrameWork2(Object o) {
}
}

теперь вы можете использовать методы getAs * для "раскрытия" вашего класса

2023-09-24 16:31 java