Czy powinienem wdrożyć interfejs bezpośrednio, czy też powinien to zrobić superklasa?

14

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 AbstractBmoż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”?

c_maker
źródło
3
sugestia w tytule: czy powinienem wdrożyć interfejs bezpośrednio, czy też powinien to zrobić superklasa
Jeanne Boyarsky,

Odpowiedzi:

20

Wszystko zależy, jeśli AbstractB implements Csemantycznie. Tj. Jeśli ma to sens semantyczny dla AbstractBwdrożenia C, 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

class Dog extends Animal implements IBark{

To nie ma sensu, ponieważ oznaczałoby to, że wszystkie zwierzęta szczekają.

class Animal implements IBark{

Inne różnice wchodzą w grę, jeśli masz więcej niż tylko class Adziedziczenie AbstractB. W nr 1 nie muszą implementować C, w nr 2 wszyscy są zmuszeni do implementacji C.

Karthik T.
źródło
1
+1 O wiele bardziej jasne niż moja odpowiedź!
Hand-E-Food,
Dodatkowo, jeśli interfejs Heterotrophbyłby rozsądny, to Animalimplementować Heterotroph. Jeśli oczekujesz wielu innych szczekających zwierząt i chcesz traktować je w ten sam sposób, kolejna klasa BarkingAnimal extends Animal implements IBarkbyłaby dobrym rozwiązaniem.
scarfridge
@scarfridge Właściwie spodziewałbym się, że zwierzę się przedłuży, Heterotrophale dzięki za twój wkład
Karthik T
2

Ł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();lub otherObject.addAbstractB(this);. Tak czy inaczej, później użyjesz tego AbstractBodwołania do wykonania różnych wywołań metod.

Czy w tej sytuacji chcesz wywołać metody C? Jeśli tak, to AbstractBnależ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.

Karl Bielefeldt
źródło
2

To nie jest „ukryty” cel dokumentacji. Pozwala rzutować AbstractB i wszystkie jego podklasy na C. Istnieją w rzeczywistości trzy style.

public class A extends AbstractB implements C
public class AbstractB

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.

public class A extends AbstractB
public AbstractB implements C

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.

public class A extends AbstractB implements C
public class AbstractB implements C

Ten jest zbędny, ale może zwiększyć przejrzystość.

Jeanne Boyarsky
źródło
Myślę, że „AbstractC” (który nie istnieje w pytaniu) w drugim akapicie należy zmienić na „AbstractB”. Nie mogę tego zrobić, ponieważ edytorzy muszą mieć co najmniej 6 znaków.
cellepo