Java – вызов имени метода при реализации интерфейса

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

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

Нет, не существует способа реализовать один и тот же метод двумя разными способами в одном classе 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 из двух classов, каждый из которых реализует другой интерфейс. Тогда этот class будет иметь поведение обоих интерфейсов.

 class CompositeClass { ISomething class1; ISomething2 class2; void doSomething1(){class1.doSomething();} void doSomething2(){class2.doSomething();} } 

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

 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 от AlfaBeta до Beta , downcasts обычно злые, и если можно ожидать, что экземпляр Alfa часто также имеет Beta аспект, и по какой-либо причине (как правило, оптимизация – единственная действительная причина), вы хотите, чтобы иметь возможность конвертировать его в Beta , вы можете создать под-интерфейс Alfa с Beta asBeta() в нем.

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

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

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

«Классическая» проблема Java также влияет на развитие Android …
Причина кажется простой:
Больше фреймворков / библиотек, которые вы должны использовать, проще всего, что вы можете выйти из-под контроля …

В моем случае у меня есть class BootStrapperApp, унаследованный от android.app.Application ,
тогда как тот же class должен также реализовать интерфейс платформы MVVM для интеграции.
Метод collision произошел в методе getString () , который объявляется обоими интерфейсами и должен иметь различную реализацию в разных контекстах.
Обходной путь (уродливый..IMO) использует внутренний class для реализации всех методов платформы только из-за одного конфликта подписи второстепенного метода … в каком-то случае такой заимствованный метод вообще не используется (но затрагивает основную семантику дизайна) ,
Я склонен соглашаться, что C # -строчный явный контекст / пространство имен полезно.

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

например: предположим, что у вас есть 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); } } 

В конечном итоге class, который вы хотели, должен что-то вроде

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

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

Все хорошо и хорошо, когда у вас есть полный контроль над всем кодом, о котором идет речь, и можете реализовать этот аванс. Теперь представьте, что у вас есть существующий открытый class, используемый во многих местах с помощью метода

 public class MyClass{ private String name; MyClass(String name){ this.name = name; } public String getName(){ return name; } } 

Теперь вам нужно передать его на полке WizzBangProcessor, которая требует, чтобы classы реализовали WBPInterface … который также имеет метод getName (), но вместо вашей конкретной реализации этот интерфейс ожидает, что метод вернет имя типа Wizz Bang Processing.

В C # это будет trvial

 public class MyClass : WBPInterface{ private String name; String WBPInterface.getName(){ return "MyWizzBangProcessor"; } MyClass(String name){ this.name = name; } public String getName(){ return name; } } 

В Java Tough вам придется идентифицировать каждую точку существующей развернутой базы кода, где вам нужно преобразовать из одного интерфейса в другой. Конечно, компания WizzBangProcessor должна была использовать getWizzBangProcessName (), но они тоже разработчики. В их контексте getName было в порядке. На самом деле, за пределами Java, большинство других языков, основанных на OO, поддерживают это. Java редко встречается в принуждении всех интерфейсов к реализации с помощью того же метода NAME.

На большинстве других языков есть компилятор, который более чем счастлив взять инструкцию, чтобы сказать «этот метод в этом classе, который соответствует сигнатуре этого метода в этом реализованном интерфейсе, является его реализацией». После того, как весь смысл определения интерфейсов должен позволить абстрагироваться от реализации. (Даже не заставляйте меня начинать с использования методов по умолчанию в интерфейсах на Java, не говоря уже о переопределении по умолчанию …. потому что конечно, каждый компонент, предназначенный для дорожного автомобиля, должен быть способен захлопнуться в летающем автомобиле и просто работать – эй они оба являются машинами … Я уверен, что функциональность по умолчанию, скажем, ваша спутниковая навигационная система не будет затронута стандартными входами подачи и подачи, потому что автомобили только рыскают!

Давайте будем гением компьютера.