2013-10-25 4 views
10

У меня есть два интерфейса, которые должны исключать друг друга:Можно ли сделать два интерфейса Java взаимоисключающими?

interface Animal{} 
interface Cat extends Animal{} 
interface Bird extends Animal{} 

Как я могу предотвратить реализацию класса, который реализует как Cat и Bird интерфейсы?

class Impossible implements Cat, Bird{} 
+2

Не уверен, что это соответствует вашему прецеденту (я полагаю, что животные - это всего лишь пример), но вы не можете использовать абстрактные классы «Cat» и «Bird»? –

+0

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

+1

'// Не реализуйте этот интерфейс вместе с Bird, потому что ...' – zch

ответ

9

Наконец грязный раствор:

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 

дрозд наклоняет быть реализован, потому что:

интерфейса животные не могут быть реализованы более чем один раз с различными аргументами: Animal < Птицы> и животными < Cat>

+1

Я не думаю, что это совсем грязно. На самом деле, это самый ясный ответ, который я нашел для этого вопроса, первоклассный. Хорошее использование дженериков. – EpicPandaForce

+1

Да. Несовместимость интерфейсов - это правильный способ обеспечить взаимную эксклюзивность. –

+0

@ RyanYoosefi Серьезно? Я боюсь моего вопроса и у него много оборотов. Начиная с идеи о том, что Bird and Cat - это интерфейс! Позвольте мне спросить моих коллег: «Если птица будет разработана как интерфейс?» они будут кричать «Черт возьми!». Всякий раз, когда Cat и Bird являются классами, они, естественно, исключаются. Но другие примеры, такие как Immortal и Mortal, являются лучшими примерами исключения интерфейса, чем Bird and Cat. Arrrrr! (а не Arrrr, как сумасшедший, Arrrr, как совершить ток-пиратский день) –

3

Интерфейсы на Java рождаются для реализации. Любой класс может реализовать любой интерфейс, если захочет. Поэтому я думаю, что нет способа предотвратить этот случай. Вероятно, вам нужно пересмотреть свой дизайн.

+0

Я понятия не имею о редизайне. Пожалуйста, дайте подсказку. –

+1

Как показывают другие, существуют (и хорошие, и плохие) способы предотвратить это. –

0

Java не предоставляет синтаксис, который предотвратит реализацию одним классом двух разных интерфейсов. Это хорошо, потому что интерфейсы должны позволить вам забыть о том, с каким объектом вы имеете дело, и сосредоточиться только на функциях, связанных с этим интерфейсом.

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

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

Наилучший подход, если вы должны заставить это отношение answer provided by NickJ.

+1

На самом деле, если программист определяет оба интерфейса, он может его предотвратить. См. Мой ответ. – Torben

+0

@Torben Java не предназначен для предотвращения одновременного внедрения двух интерфейсов. Конечно, вы заметили обход, но это не меняет того факта, что Java на самом деле не намерен вас предотвращать. Таким образом, я думаю, что мой ответ все еще стоит. –

+0

Вопрос не в том, предназначена ли Java для этого, или нет. Вопрос был, если это возможно. Вы ищете оправдания для своего ответа, хотя _facts_ доказывают это неверно. – Torben

2

возможно, вы не можете предотвратить. возможно, вы можете заменить Cat и Bird абстрактным классом, а Impossible может только расширять его.

3

Существует действительно очень уродливое обходное решение. Внедрить сигнатуру противоречивого метода для интерфейсов 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 { 
} 

Но не делайте этого. Подумайте лучше.

+0

'Cat getNaturalParent();' и 'Bird getNaturalParent();' может совпадать .... –

+0

Возможно, это должно быть в интерфейсе Animal: Animal getNaturalParent(); То, что мы здесь делаем, - это уродливый хак. Мы не должны пытаться использовать его в фактическом дизайне. Лучше держите взломать как абсолютно бесполезный побочный метод, который никогда не используется ни в чем другом. И укажите, почему хак существует в JavaDocs. – Torben

+3

Кроме того, не позволяя животным Cat-Bird дисквалифицировать мифических существ, таких как http://en.wikipedia.org/wiki/Lion_of_Venice – Torben

9

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

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

пример:

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

+0

Не знаете, почему это имеет проголосовавший голос ... –

+2

Ни я, ни я. Доводчики действительно должны обеспечивать обратную связь. – NickJ

+0

Я не спускал вниз, но ваш ответ, но * Интерфейс! = Абстрактный класс *, поэтому я не поднял верх. И быть или не быть: 'CanFly' - это государство! Я не спускал вниз, потому что я могу бросать исключение IllegalState везде, где мне нравится. –

0

Вы много сгенерирует исключение, когда класс собирается использовать его, 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); 
    } 
} 
+5

Даже если Mutant BirdCat не будет долго жить ... Это должно быть проблемой времени компиляции. –

+0

для парня 'BirdCat', у вас будет другой интерфейс интерфейса BirdCat реализует Animal {}' –

+0

Я согласен с @PeterRader, решение этого с проверкой времени выполнения не является хорошим решением. –

1

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

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

Смежные вопросы