2012-10-29 10 views
5

Kiedy zatrudnić biegle podejście może mieć następujący scenariusz:Java - dziedziczone Płynna typu metoda powrotu do powrotu klasy incydent typ, a nie rodziców

public class Foo<T extends a>{ 

    public Foo<T> someMethod(){ 
      System.out.println("foo"); 
      return this; 
    } 

} 


public class Bar<T extends b> extends Foo<T> { 

     public Bar<T> barMethod(){ 

      System.out.println("bar"); 
      return this; 
     } 

} 


public class a{} 
public class b extends a{} 

Siłą płynny interfejs jest to, że można łańcuch sposób wywołania, ale podczas gdy Bar dziedziczy metodę someMethod(), typ zwracany jest Foo bar, który nie pęknie następujący łańcuch:

new Bar<b>().someMethod().barMethod(); 

Jedna odpowiedź mogła być dodanie @Overrides dla każdego odziedziczonej metody, takie, że bar ma dodatkowa metoda:

@Override 
public Bar<T> someMethod(){ 
      System.out.println("foo"); 
      return this; 
    } 

Ale w dużych klasach i rozbudowanej hierarchii klas może to z pewnością okazać się bałaganem redundancji ?! Czy istnieje odpowiedni typ zwrotu, który zapewnia płynne metody, dzięki którym każda klasa, która go dziedziczy, zwróci obiekt swojego określonego typu (tak abyśmy mogli łączyć metody bez rzutowania)?

Próbowałem:

 public <U extends Foo<T>> U someMethod(){ 
      System.out.println("foo"); 
      return this; 
    } 

Do niestety, bezskutecznie. Mam nadzieję, że ktoś wie o prostym i eleganckim rozwiązaniu tego problemu. Projekt jest duży i dlatego musi być w miarę możliwości utrzymywany i rozszerzalny.

Dziękujemy za pomoc w tym scenariuszu.

Odpowiedz

5

Można zrobić to w ten sposób, jeśli nie przeszkadza niesprawdzany Obsada:

public class Foo<T, F extends Foo<T, F>> { 
    public F someMethod() { 
    System.out.println("foo"); 
    return (F) this; // <--- That's the unchecked cast! Tucked safely away. 
    } 
    public static void main(String[] args) { 
    new Bar<String>().someMethod().barMethod(); 
    } 
} 

class Bar<T> extends Foo<T, Bar<T>> { 
    public Bar<T> barMethod() { 
    System.out.println("bar"); 
    return this; 
    } 
} 

Osobiście wyłączyć niezaznaczone obsady ostrzeżenie globalne dla całego projektu.

+0

Ale nadal istnieje "casting", którego OP nie chce. Nie wiem dlaczego. Umm. Ale ten rzut jest lepszy. Jest w jednym miejscu. Tak więc OP powinno być w porządku z tym. Else Lord pomóż mu. ;) –

+1

@RohitJain zobacz komentarz Dokonałem powyższej odpowiedzi: jest to użyteczność, starając się uczynić ją prostą w użyciu, aby klient mógł dołączyć do swojego projektu. Rozwiązanie Marko Topolnika jest jednak interesujące i coś, czego nie brałem pod uwagę. Wydaje się, że odlewy jakiegoś opisu są nieuniknione? – ComethTheNerd

+0

@MarkoTopolnik. Tak, dlatego na końcu mojego komentarza dodałem, że jest to lepszy rzut, jak w jednym miejscu.:) –

1

Co można zrobić, to zdefiniować streszczenie metody barMethod, aby można było teraz wywoływać ją na typie Foo.

public abstract class Foo<T extends a> { 

    public Foo<T> someMethod() { 
     System.out.println("foo"); 
     return this; 
    } 

    public abstract Foo<T> barMethod(); 
} 

Teraz można łatwo wywołać

new Bar<b>().someMethod().barMethod(); 
+0

Problem z tym podejściem polega na tym, że uniemożliwia on nam utworzenie instancji Foo bezpośrednio, co musi być możliwe do zrobienia. – ComethTheNerd

+0

@ KodHodowania. Nie chcesz więc dodawać metody abstrakcyjnej, nie chcesz jej zastępować, a nie chcesz typować. Hmmm. Będzie ciężko, jeśli będzie jakiś sposób. Zobaczmy, czy ktoś może wymyślić rozwiązanie. Ale nie sądzę, że istnieje obejście, jeśli wyeliminujesz wszystkie obejścia. ale wciąż nie mogę być tego pewien. –

+0

Wtedy będziesz musiał go rzucić. –

Powiązane problemy