2015-05-13 7 views
37

Powiedzmy mam następujący interfejs:Jak zastosować więcej ograniczeń dla deklaracji interfejsu w Javie?

interface Mammal { 
    void marry(Mammal m); 
    Mammal giveBirthTo(); 
} 

to jednak nie powiedzieć dość dokładnie, czego chcę.

Oczywiście człowiek nie może poślubić psa, ani nie może urodzić kota. Jak mogę osadzić te informacje w interfejsie, aby typ wejścia i typ wyjścia mógł być zmieniany automatycznie po jego zaimplementowaniu?

Odpowiedz

47

Możesz użyć generycznych i zmienić swój projekt.

Coś w linii:

interface Marriable<T extends Mammal> { 
    void marry(T sweetHalf); 
    T giveBirthTo(); 
} 

... gdzie Mammal to top interfejs lub klasa abstrakcyjna i Human, Dog, Unicorn itp przedłużyć/wdrożyć.

+2

Czy interfejs nie powinien mieć nazwy "Mammal"? Nie ma powodu do dodawania kolejnego. –

+1

@RafaelWinterhalter, a jak już wspomnę, możesz mieć interfejs 'Mammal' lub abstrakcyjną klasę abstrakcyjnego zwierzęcia w tym szczególnym łańcuchu dziedziczenia. Interfejs 'Marriable' określałby umowę o zawarciu małżeństwa z jednym z twoich gatunków. – Mena

+0

Nie potrzebujesz do tego interfejsu 'Marriable'. Możesz po prostu utworzyć typ rekursywny, jak zasugerowałeś w odpowiedzi, którą właśnie dodałem. –

1

Generics. Spróbuj z

private static interface Race { 
} 

private static class Human implements Race {} 
private static class Canine implements Race {} 

private static interface Being<R extends Race> { 
    void marry(Being<R> other); 
    Being<R> giveBirthTo(); 
} 

private void tryMe() { 
    Being<Human> aHuman = new Being<Human>() { 

     @Override 
     public void marry(Being<Human> other) { 
     } 

     @Override 
     public Being<Human> giveBirthTo() { 
      return null; 
     } 
    }; 

    Being<Canine> aCanine = new Being<Canine>() { 

     @Override 
     public void marry(Being<Canine> other) { 
     } 

     @Override 
     public Being<Canine> giveBirthTo() { 
      return null; 
     } 
    }; 

    aHuman.marry(aCanine); // not possible 
} 
23

Można generify interfejsu przy użyciu zmiennej typu rekurencyjnego:

interface Mammal<T extends Mammal<T>> { 
    void marry(T m); 
    T giveBirthTo(); 
} 

ten sposób kompilator Javy może dać pewien poziom sprawdzania poprawności. Zauważ jednak, że to podejście jest nadal otwarte na nadużycia. Na przykład:

class Cat implements Mammal<Cat> { 
    @Override void marry(Cat cat) { ... } 
    @Override Cat giveBirthTo() { ... } 
} 

class Dog implements Mammal<Cat> { // implements wrong interface 
    @Override void marry(Cat cat) { ... } 
    @Override Cat giveBirthTo() { ... } 
} 

Kompilator może jedynie zapewnić, że można zaimplementować interfejs Mammal przez jakiś Podtyp tego samego interfejsu, ale nie przez poszczególne klasy, która implementuje go. Tego ostatniego ograniczenia typu nie można wyrazić w języku programowania Java.

+5

Dla Twojej przyjemności z Google, nazywa się to * ilościowym oznaczeniem F *. –