Можно ли сделать два интерфейса Java взаимоисключающими?
У меня есть два интерфейса, которые должны исключать друг друга:
interface Animal{}
interface Cat extends Animal{}
interface Bird extends Animal{}
Как я могу предотвратить реализацию класса, который реализует интерфейсы Cat
и Bird
?
class Impossible implements Cat, Bird{}
Ответы
Ответ 1
Наконец, грязное решение:
public interface Animal<BEING extends Animal> {}
public interface Cat extends Animal<Cat> {}
public interface Bird extends Animal<Bird> {}
public class CatBird implements Cat, Bird {} // compiler error
public interface CatBird extends Cat, Bird {} // compiler error
CatBird не может быть реализован, потому что:
Интерфейс Animal не может быть реализован более одного раза с разными аргументами: Animal <Bird> и Animal <Cat>
Ответ 2
Здесь у вас четкая иерархия - корень с ветвями, и, очевидно, node (класс, интерфейс, что угодно) не может быть на нескольких ветвях. Для обеспечения этого используйте абстрактные классы вместо интерфейсов.
Интерфейсы могут использоваться, когда есть какой-то сквозной аспект, который может быть разделен между любыми классами вашей иерархии и где два интерфейса не являются взаимоисключающими.
Пример:
public abstract class Animal;
public interface CanFly;
public interface CanHunt;
public abstract class Cat extends Animal implements CanHunt;
public abstract class Bird extends Animal implements CanFly;
public class Vulture extends Bird implements CanHunt; //also CanFly because of Bird
По крайней мере одна другая рассмотрела эту проблему: http://instantbadger.blogspot.co.uk/2006/10/mutually-exclusive-interfaces.html
Ответ 3
Рождаются интерфейсы в Java. Любой класс может реализовать любой интерфейс, если захочет. Поэтому я думаю, что нет способа предотвратить этот случай. Вероятно, вам нужно пересмотреть свой дизайн.
Ответ 4
Есть действительно, действительно уродливое обходное решение. Внедрить сигнатуру конфликтующего метода для интерфейсов Cat и Bird:
public interface Cat {
int x();
}
public interface Bird {
float x();
}
/**
* ERROR! Can not implement Cat and Bird because signatures for method x() differ!
*/
public class Impossible implements Cat, Bird {
}
Но не делайте этого. Определите лучший способ вместо этого.
Ответ 5
Вероятно, вы не можете предотвратить. возможно, вы можете заменить Cat
и Bird
абстрактным классом, а Impossible может только расширять его.
Ответ 6
Не уверен, что это помогает, но если вы не укажете, что интерфейс является общедоступным, ваш интерфейс будет доступен только для классов, определенных в том же пакете, что и интерфейс.
Итак, вы можете поместить свой интерфейс в один пакет и любые классы, которые вы не хотите реализовать в другом.
Ответ 7
Java не предоставляет кусок синтаксиса, который предотвратит реализацию одним классом двух разных интерфейсов. Это хорошо, потому что интерфейсы должны позволить вам забыть о том, с каким объектом вы имеете дело, и сосредоточиться только на функциональности, связанной с этим интерфейсом.
В случае с животными это может показаться запутанным, потому что в реальной жизни ни одно животное не является кошкой и собакой. Но нет причин, чтобы один Java-класс не мог выполнить контракт как интерфейса Cat
, так и интерфейса Dog
. Если вы хотите обосновать это на самом деле, рассмотрите коробку, содержащую как кошку, так и собаку!
Теперь, как указывают Торбен и другие, вы можете сознательно вводить методы в интерфейс, который будет сталкиваться с методами в другом интерфейсе. Это приведет к тому, что Java запретит использование обоих интерфейсов в одном классе. Но по причинам, перечисленным выше, это не очень хорошая работа для рассмотрения.
Лучший подход, если вы должны заставить это отношение, - это ответ, предоставленный NickJ.
Ответ 8
Вы много бросаете исключение, когда класс собирается его использовать, UML Diagram хотел бы этого
![enter image description here]()
как вы видите выше, Possible
будет реализовывать либо Cat
, либо Bird
, но не оба. но это всего лишь диаграмма, поэтому функциональность будет такой.
interface Animal{void x();}
interface Cat extends Animal{}
interface Bird extends Animal{}
class Impossible implements Cat, Bird{
@Override
public void x() {
System.out.println("Oops!");
}}
class Possible implements Cat{
@Override
public void x() {
System.out.println("Blah blah");
}
}
class Core {
private Animal a;
public void setAnimal(Animal a) throws Exception {
if (a instanceof Cat && a instanceof Bird) {
System.out.println("Impossible!");
throw new Exception("We do not accept magic");
}
this.a = a;
a.x();
}
public static void main(String[] args) throws Exception {
Core c = new Core();
Possible p = new Possible();
c.setAnimal(p);
Impossible ip = new Impossible();
c.setAnimal(ip);
}
}