2015-04-07 10 views
5

Pytanie jest proste, ale nie jestem pewien, że to możliwe, aby to zrobić ...Jak rozszerzyć klasę, która wraca to w swoich metodach

jeśli mamy klasę jak

class A { 
    private int foo; 

    public A(int bar) { 
     this.foo = bar; 
    } 

    public A setFoo(int bar) { 
     this.foo = bar; 
     return this; 
    } 

    public int getFoo() { 
     return this.foo; 
    } 

    public void doSomething() { 
     this.foo++; 
    } 
} 

widzimy, że jest to po prostu klasa z prywatnym członkiem i seter/getter. Ciekawostką jest, że w celu umożliwienia łączenia metod, setter wraca this.

Więc możemy robić rzeczy tak:

A a = new A(0); 
a.setFoo(1).doSomething(); 

Problem polega na tym, kiedy staram się rozszerzyć, że klasa dodać niektóre funkcje wykonawcze interfejs podobny do tego

class B extends A implements I { 
    public B(int bar) { 
     this.super(bar); 
    } 

    public void methodI() { 
     // whatever 
    } 
} 

To wydaje się ok, dopóki Zaczynam go używać w ten sposób:

B b = new B(1); 
b.setFoo(2).methodI(); 

Ponieważ setFoo jest rzeczywiście retu rning wystąpienie A, a nie instancja B, aw A methodI nie istnieje ...

Jakiekolwiek obejście? Dzięki.

Nawiasem mówiąc, po prostu napisał podstawowy kod wystarczy, aby zrozumieć, ale jeśli chcesz wiedzieć więcej, jestem po prostu staramy się rozszerzyć niektóre z podstawowych klas libgdx (jak Math.Vector2, Math.Vector3) do implementuj Poolable.

+0

Czy próbowałeś rzucić? '((B) b.setFoo (2)). methodI() '? –

+0

@Ori Lentz Tak, ale nie mam ochoty na casting za każdym razem, gdy wydaje się, że jest bardziej naturalna odpowiedź. Oczywiście nie wiem, czy to możliwe, więc pytam przed napisaniem jakiegoś brudnego kodu: P – danikaze

+0

Dlaczego potrzebujesz wektory do wdrożenia Poolable? Nie muszą tego implementować, aby móc pracować z pulą i zazwyczaj zawsze masz jakąś wartość, aby początkowo ją ustawić, gdy ją uzyskasz, więc naprawdę nie ma potrzeby stosowania metody "reset()". Powodem, dla którego pytam, jest to, że jeśli istnieje dobry powód, równie dobrze można go dodać do źródła. – Tenfour04

Odpowiedz

5

Klasa B może zastąpić metodę setFoo i zmienić wartość r eturn type to B, ponieważ B jest bardziej szczegółową wersją A. Nadpisywana metoda może mieć bardziej specyficzny typ zwracania. na przykład

class B extends A implements I { 
    public B(int bar) { 
     this.super(bar); 
    } 

    public void methodI() { 
     // whatever 
    } 

    @Override 
    public B setFoo(int bar) { 
     this.foo = bar; 
     return this; 
    } 
} 
+0

Tak, to pierwsze rozwiązanie, które myślałem, a nawet ponowne wprowadzenie klasy z kopiuj-wklej, ponieważ nie mogę jej ponownie użyć ... ale ...szukałem obejścia, więc nie muszę przepisywać wielu metod (Jeśli spojrzysz na klasy libgdx, istnieje wiele metod w kilku klasach, takich jak Vector2, Vector3, itp. To nie tylko bezpośredni ustawiacze, ale także wiele metod przeprowadzania operacji modyfikacji wewnętrznych danych klas rzeczywistych) – danikaze

+0

Jeśli chcesz zmienić typ zwracania, musisz nadpisać sygnaturę metody. Ale możesz zapisać część kopii i wkleić, wywołując instancję metody supers zamiast ponownego implementacji. na przykład @Override public B setFoo (int bar) { super.setFoo (bar); zwróć to; } – bhspencer

+0

Ponieważ nie mogę zmodyfikować kodu biblioteki libgdx, ponieważ jest to słoik (i prawdopodobnie dlatego, że nie będzie to dobry pomysł, jeśli zostanie zaktualizowany), przejdę do twojej odpowiedzi i oznaczy ją jako prawidłową. jeden ... ale postaram się również złożyć prośbę o pociągnięcie z odpowiedzią zaproponowaną przez Bedrin, ponieważ uważam, że jest to "poprawny" – danikaze

-2

Wystarczy setFoo() void powrotny, a następnie można zrobić:

B b = new B(1); b.setFoo(2); b.methodI();

+2

OP chce funkcji "zwróć to". –

+0

W takim przypadku mogę po prostu zignorować wartość zwracaną i zrobić to w dwóch różnych liniach tak, ale pytałem o obejście, aby użyć tej funkcji ... – danikaze

2

Należy użyć rodzajowych tutaj:

public class A<T extends A<?>> { 

    public T self() { 
     return (T) this; 
    } 

    private int foo; 

    public A(int bar) { 
     this.foo = bar; 
    } 

    public T setFoo(int bar) { 
     this.foo = bar; 
     return self(); 
    } 

    public int getFoo() { 
     return this.foo; 
    } 

    public void doSomething() { 
     this.foo++; 
    } 

} 

public class B<T extends B<?>> extends A<T> implements I { 

    public B(int bar) { 
     this.super(bar); 
    } 

    public void methodI() { 
     // whatever 
    } 
} 

Teraz będzie można korzystać z takich łańcuchu połączeń :

B b = new B(1); 
b.setFoo(2).methodI(); 
+0

Pamiętaj, że nie stworzyłem klasy A, ale już ją otrzymałem. – danikaze

+0

Ponieważ nie mogę zmodyfikować kodu biblioteki libgdx, ponieważ jest to słoik (i prawdopodobnie dlatego, że nie będzie to dobry pomysł, jeśli zostanie zaktualizowany), pójdę z odpowiedzią bhspencer i oznaczy ją jako prawidłową. .. ale postaram się również poprosić o odpowiedź, ponieważ uważam, że jest to "poprawny"! – danikaze

1

Zrobiłem to również wcześniej. Nie myśl, że jest proste rozwiązanie. Rozważmy nadrzędnymi wszystkie metody ustawiające:

class B extends A implements I { 
    @Override 
    public A setFoo(int bar) { 
     super.setFoo(bar); 
     return this; 
    } 
} 
+3

Masz na myśli 'public B setFoo'? – thefourtheye

+0

Tak, to pierwsze rozwiązanie, które myślałem, a nawet ponowne wdrożenie klasy z kopiuj-wklej, ponieważ nie mogę jej użyć ponownie ... ale ... szukałem obejścia, więc nie muszę przepisywać wielu metody (to nie tylko bezpośredni ustawiacze, ale także wiele metod wykonywania operacji modyfikacji wewnętrznych danych prawdziwych klas) – danikaze

0

Dla kompletności (tzn ja nie uważam tego za lepszą rozwiązanie niż wymienione powyżej, po prostu może być właściwe) i na pewno nie jest to odpowiedź na tytule pytanie, ale możliwe rozwiązanie twojego problemu.

Można rozważyć zastosowanie metod oferowanych przez Javę 8. Jest to szczególnie przydatne w celu dodania funkcjonalności do istniejących klas.

// From LibGDX Pool.Poolable 
interface Poolable { 

    public void reset(); 
} 

// Class A untouched. 
class A { 

    private int foo; 

    public A(int bar) { 
     this.foo = bar; 
    } 

    public A setFoo(int bar) { 
     this.foo = bar; 
     return this; 
    } 

    public int getFoo() { 
     return this.foo; 
    } 

    public void doSomething() { 
     this.foo++; 
    } 
} 

// Extend Poolable to add the functionality. 
interface PoolableVector extends Poolable { 

    default void reset() { 
     // Not sure what you want to do here. 
    } 
} 

// A Poolable A trivially made. 
class B extends A implements PoolableVector { 

    public B(int b) { 
     super(b); 
    } 

} 
+0

Nie jestem tego pewien, ale ... Po pierwsze, myślę, że nie możesz użyć Java 8 z Androidem jeszcze ... Po drugie, jeśli nie używasz domyślnych metod, ale wdrażasz resetowanie w klasie B, myślę, że otrzymujesz taki sam wynik ??? Który próbuje wywołać B.doSomething na obiekcie zwróconym przez A.setFoo podczas wywoływania b.setFoo(). DoSomething(), jak wyjaśniłem w pytaniu ... Popraw mnie, jeśli się mylę ... – danikaze

Powiązane problemy