2016-02-20 14 views
6

Java - Czy można rozszerzyć wszystkie podklasy klasy o jedną klasę?Java - Czy można rozszerzyć wszystkie podklasy klasy o jedną klasę?

Wyjaśnijmy to na przykładzie, rzeczywisty kod jest bardziej skomplikowany. Mam klasę zwierząt z własną hierarchią klas. Powiedzmy, że ma dwie podklasy: Testarrosa i Viper.

public class Car { 

    public abstract String getManufacturer(); 
} 

public class Testarossa extends Car{ 

    public String getManufacturer(){ 
     return "Ferrari"; 
    } 
} 

public class Viper extends Car{ 

    public String getManufacturer(){ 
     return "Dodge"; 
    } 
} 

Chcę rozszerzyć wszystkie podklasy Car z podklasą RegisteredCar.

public class RegisteredCar extends Car { 

    private String plateNumber; 

    public RegisteredCar (String plateNumber){ 
     this.plateNumber=plateNumber; 
    } 

    public String getPlateNumber() { 
     return plateNumber; 
    } 
} 

W pewnym momencie powinienem być w stanie utworzyć nowy RegisteredCar określonej podklasy. Coś jak

RegisteredCar c = new RegisteredCar<Viper>("B-3956-AC"); 

i wywołać c.getManufacturer(), aby uzyskać "Dodge" i c.getPlateNumber(), aby uzyskać B-3956-AC. Oczywiście nadal powinienem być w stanie stworzyć taki przykład. Posiadanie atrybutu w samochodzie o wartości pustej, jeśli nie jest zarejestrowany, nie jest wystarczające dla tego, czego potrzebuję.

+3

* "Załóżmy, że ma dwie podklasy: Goryl i Wilk" * .. Przypuszczam, że powinieneś trzymać się przykładu "Samochód";). – Tom

+0

ale nie, nie można tego zrobić. –

+0

Czy nie można zmienić klasy bazowej Vipera i Testarossy na RegisteredCar? – sfThomas

Odpowiedz

4

Jak mówili inni, no to jest to naprawdę niemożliwe a przykładem może być rozwiązany poprzez zmianę modelu

Jako alternatywę do dziedziczenia można użyć innej klasy do zawijania instancji Car.
chciałbym zrobić Car interfejs (mimo posiadania RegisteredCar przedłużyć Car powinien pracować zbyt), a następnie próbować coś podobnego do następującego kodu pseudo:

class RegisteredCar<T extends Car> implements Car { 
    private final T car 

    RegisteredCar(T car) { 
    this.car = car; 
    } 

    ... methods for RegisteredCar 
    ... methods from Car delegating to `this.car` 
} 

Proszę usprawiedliwić nieco zły kod, nie mam IDE otwarty i zawsze mylę generics bez IDE do ręki.

Innym możliwym rozwiązaniem jest użycie AOP, choć nie wiem jak w modzie to jest obecnie, ale to, co opisujesz, może stanowić problem przekrojowy.

Ostateczna Alternatywą może być użycie języka, który pozwala na Extensions, cechy, protokołu lub innego typu „mix”

+1

Tak jak powiedziałem do Bhushana, nie jest to doskonałe; ale jest to najlepsze rozwiązanie, jakie do tej pory znalazłem. Niestety musi to być Java :( –

+0

Dzięki :). To nie jest doskonałe, ale jeśli ograniczasz się do Javy, to czasami musisz poradzić sobie z niedociągnięciem tego języka, żaden język ogólnego przeznaczenia nie jest idealny. Szkoda jednak, że JVM ma kilka świetnych języków z Java interop, ale wydaje się niemożliwe, aby przekonać "liderów" do miksowania w trochę innych językach, gdy jest to właściwe. Powodzenia. – Gavin

2

W języku java zabronione jest wydawanie więcej niż jednej klasy. Można na przykład zbudować łańcuch od klas do rozszerzeń. Aby rozwiązać problem wielokrotnego dziedziczenia w Java → interfejs jest używany

+1

To nie jest problem wielokrotnego dziedziczenia. Nie próbuję utworzyć jednej klasy, która dziedziczy z wielu klas. Jest to kwestia dziedziczenia rodzajowego; nie wiesz, którą klasę rozszerzasz. –

10

Krótko mówiąc, nie jest to niemożliwe. Musisz niestety zmodyfikować swój model obiektowy.

Na przykład, co o konieczności klasa Registration ten sposób:

public interface Registration<C extends Car> { 
    C getCar(); 

    String getPlateNumber(); 
} 

ten sposób można wyodrębnić informacje odnoszące się do rejestracji w jednej klasie, zachowując swoje modele Car.

Można wtedy zrobić pomocnika metod takich jak:

Registration<Viper> registeredViper = createRegistration(new Viper(), "B-3956-AC"); 
+0

Ah! Niemal taka sama jak moja odpowiedź. Po prostu zmusiłbym go do implementacji interfejsu 'Car', a następnie może być użyty tam, gdzie' Car' był używany, wystarczy delegować zaimplementowane metody do owiniętej instancji 'Car'. Wznowiono odpowiedź. – Gavin

1

Nie, to nie jest tak, jak C++. Dziedziczenie wielokrotne nie jest możliwe w Javie. Możesz jednak wdrożyć wiele interfejsów.

+1

To nie jest problem wielokrotnego dziedziczenia. Nie próbuję utworzyć jednej klasy, która dziedziczy z wielu klas. Jest to kwestia dziedziczenia rodzajowego; nie wiesz, którą klasę rozszerzasz. –

0

Nie można tego osiągnąć z dziedziczeniem. Najlepszym rozwiązaniem jest dokonanie typ RegisteredCar rodzajowy, a następnie o rodzajowy instancji zmienną, która przechowuje zamierzony typ samochodu:

public class RegisteredCar<T extends Car> { 
    private String plateNumber; 
    private T car; 

    public T getCar() { 
     return this.car; 
    } 
    public T setCar(T car) { 
     this.car = car; 
    } 
    public RegisteredCar (String plateNumber){ 
     this.plateNumber=plateNumber; 
    } 
    public String getPlateNumber() { 
     return plateNumber; 
    } 
} 

z tym, będzie można przejść do RegisteredCar obiekt dowolnego typu, który jest podklasą samochodowy.

Jak można zauważyć, usunąłem część tej klasy z extends Car, ponieważ nie musi ona być podklasą samego samochodu.

2

Należy unikać dziedziczenia tak bardzo, jak to możliwe. Użyj abstrakcji (interfejsów), aby twój kod był elegancki i konserwowalny. Po prostu google dlaczego rozszerza się zło.

public interface Car{ 
     String getManufacturer(); 
    } 

    public interface Registerable{ 
     boolean isRegistered(); 
     void register(String plateNumber); 
     void getPlateNumber(); 
    } 

    public class Viper implements Car, Registerable 
    { 
     //all methods 
    } 
+1

Dziedziczenie klas wcale nie jest złem. Twoje rozwiązanie zmusza programistę do wdrożenia typowych metod w każdej podklasie. Jak to możliwe do utrzymania? –

+1

Jeśli potrzebujesz wspólnej funkcjonalności, możesz zaimplementować tę funkcję, zlikwidować ją i skomponować tę abstrakcję dla wszystkich klas, które jej potrzebują.W ten sposób unikniesz zależności od implementacji, będziesz mógł zmienić implementację i nikt tego nie zauważy, ponieważ implementacja jest całkowicie ukryta. Nazywa się to _Composition over dziedziczenie_. Małe zmiany w nadklasie mogą zrujnować wszystkie subklasy lub spowodować subtelne błędy. Kompozycja i zależność od abstrakcji pomaga uniknąć takich problemów. – callOfCode

+0

I to nie oznacza potrzeby wprowadzania tych samych metod w kółko. Oznacza to wdrożenie wspólnej funkcjonalności w jednym miejscu, jej abstrakcję i przekazanie tej abstrakcji wszystkim klasom, które jej potrzebują. – callOfCode

1

ze standardowym podejściem klasy, jak opisano w innych odpowiedzi, nie będzie mógł użyj RegisteredCar, gdzie wymagane jest podanie obiektu Car. na przykład załóżmy, że musisz wygenerować fakturę.

Invoice getInvoice(Car c); 

W tej metodzie nie można używać RegisteredCar, ponieważ nie jest to typ samochodu. Wszystkie API, które wymagają samochodu, nie mają zastosowania do RegisteredCar. W niektórych przypadkach może być potrzebny numer rejestracyjny, a także samochód. Tam może być konieczne mapowanie numeru tablicy rejestracyjnej i samochodów. Proponuję następujące podejście oparte na Dekoracje Wzór i przekazać wzywa wszystkich samochodów do przekazany obiektu samochodem

public class RegisteredCar extends Car{ 

    public RegisteredCar(Car c, String plateNumber){ 

    }   
    @Override 
    String getColor(){ 
     c.getColor(); 
    } 
} 
+1

Zgadzam się z pierwszą częścią. Chociaż nie jest idealny, ponieważ na końcu trzymasz dwie różne instancje, i musisz wywołać nową Car() i nową RegisteredCar(), jest to dobre obejście niedociągnięcia Java. Parametryzacja klasy (rozwiązanie Gavina) idzie nieco dalej w przypadku tych metod, które wymagają określonych parametrów podklasy, np. compareTo (Viper a). –

0

Czy istnieje powód, w rzeczywistych zajęć, że nie można po prostu dodać nową funkcję do istniejącej klasy bazowej ?

public abstract class Car 
{ 
    public abstract String getManufacturer() ; 

    protected String plate_number = null ; 

    public String getPlateNumber() 
    { return this.plate_number ; } 

    public boolean isRegistered() 
    { return (this.plate_number != null) ; } 
} 
Powiązane problemy