Можно ли сделать два интерфейса 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);
  }
}