Czy jest jakaś różnica między
public class A extends AbstractB implements C
{...}
przeciw...
public class A extends AbstractB
{...}
abstract class AbstractB implements C
{...}
Rozumiem, że w obu przypadkach klasa A będzie zgodna z interfejsem. W drugim przypadku AbstractB
może zapewnić implementację metod interfejsu w C
. Czy to jedyna różnica?
Jeśli nie chcesz, aby zapewnić implementację dla którejkolwiek z metod interfejsu w AbstractB
, jaki styl powinienem używać ? Czy używanie jednego lub drugiego ma jakiś ukryty cel „dokumentacji”?
java
interfaces
abstract-class
c_maker
źródło
źródło
Odpowiedzi:
Wszystko zależy, jeśli
AbstractB implements C
semantycznie. Tj. Jeśli ma to sens semantyczny dlaAbstractB
wdrożeniaC
, to idź do niego.Jeśli weźmiemy konkretne przykłady, różnica semantyczna staje się jasna.
Jeśli A = pies, abstraktB = zwierzę, C = IBark
Jedyny sensowny wybór
To nie ma sensu, ponieważ oznaczałoby to, że wszystkie zwierzęta szczekają.
Inne różnice wchodzą w grę, jeśli masz więcej niż tylko
class A
dziedziczenieAbstractB
. W nr 1 nie muszą implementować C, w nr 2 wszyscy są zmuszeni do implementacji C.źródło
Heterotroph
byłby rozsądny, toAnimal
implementowaćHeterotroph
. Jeśli oczekujesz wielu innych szczekających zwierząt i chcesz traktować je w ten sam sposób, kolejna klasaBarkingAnimal extends Animal implements IBark
byłaby dobrym rozwiązaniem.Heterotroph
ale dzięki za twój wkładŁatwym sposobem ustalenia właściwej relacji dziedziczenia nie jest spojrzenie na same klasy, ale na kod wywołujący metody na tych klasach. Gdzieś w kodzie masz coś takiego jak
AbstractB b = new A();
lubotherObject.addAbstractB(this);
. Tak czy inaczej, później użyjesz tegoAbstractB
odwołania do wykonania różnych wywołań metod.Czy w tej sytuacji chcesz wywołać metody
C
? Jeśli tak, toAbstractB
należy wdrożyćC
. Jeśli nie, nie powinno. Jeśli nie masz takich sytuacji, nie potrzebujesz dziedziczenia i powinieneś zrezygnować z użycia kompozycji, ponieważ jest ona znacznie luźniejsza.źródło
To nie jest „ukryty” cel dokumentacji. Pozwala rzutować AbstractB i wszystkie jego podklasy na C. Istnieją w rzeczywistości trzy style.
Użyłbym tego, gdyby AbstractB nie zaimplementował logicznie C. Nawet jeśli nie dostarcza metod, może mieć znaczenie. Tak jak Dog rozszerza Animal wprowadza Wag. Wag nie ma sensu dla wszystkich zwierząt. Zauważ, że takie podejście nie wyklucza możliwości zapewnienia implementacji przez AbstractB.
Użyłbym tego, gdybym chciał, aby wszystkie podklasy zaimplementowały interfejs. I ma to sens dla wszystkich. Tak jak Beagle rozszerza AbstractDog implementuje Wag.
Ten jest zbędny, ale może zwiększyć przejrzystość.
źródło