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 * для "раскрытия" вашего класса