Dowiedz się, kiedy klasa powinna dziedziczyć z innej klasy.

Spotkałem sporo uczniów, którzy dopiero zaczynali od programowania obiektowego (OOP) i nie byli zdezorientowani, kiedy klasa powinna dziedziczyć z innej klasy. Celem tego artykułu jest zatem możliwie najjaśniejsze wyjaśnienie tej kwestii.

Kiedy stosować dziedziczenie (relacja jest-a)

Rozważ następujące klasy:

  • Zwierzę
  • Ssak
  • Pies
  • Pudel

Na podstawie naszej wiedzy ogólnej wiemy, że:

  • Ssak jest zwierzęciem (ale zwierzę może nie być ssakiem)
  • Pies to ssak (ale ssak może nie być psem)
  • Pudel to pies (ale pies może nie być pudlem)

W tym przypadku relacja is-a przekłada się na dziedziczenie.

  • Ssak jest zwierzęciem → Zwierzę jest klasą nadrzędną, a Ssak jest klasą podrzędną → Ssak dziedziczy po Zwierzę
  • Pies jestssakiem → Ssak jest klasą nadrzędną, a Pies jest klasą podrzędną → Pies dziedziczy po Ssaku
  • Pudel jestpsem → Pies jest klasą nadrzędną, a Pudel jest klasą podrzędną → Pudel dziedziczy po Psie

Przykładowa realizacja

class Animal():
    # stuff
class Mammal(Animal):
    # stuff
class Dog(Mammal):
    # stuff
class Poodle(Dog):
    # stuff

Tutaj klasa Mammal dziedziczy po klasie Animal, więc klasa Animal jest umieszczona w nawiasach w definicji klasy Mammal. To samo dla Dog i Mammal oraz Poodle i Dog.

Kiedy nie używać dziedziczenia (relacja ma-A)

Relacja ma jest często błędnie interpretowana jako dziedziczenie. Rozważ następujące klasy:

  • Firma
  • Dział
  • Pracownik

Na podstawie naszej wiedzy ogólnej wiemy, że:

  • Firma ma wiele działów (ale dział nie jest firmą)
  • Dział ma wielu Pracowników (ale Pracownik nie jest Działem)

Tutaj relacja ma nie przekłada się na dziedziczenie. Dział nie powinien dziedziczyć po Firmie, a Pracownik nie powinien dziedziczyć po Departamencie.

Przykładowa realizacja

class Company():
    def __init__(self):
        self.departments = []
class Department():
    def __init__(self):
        self.employees = []
class Employee():
    # stuff

Zauważ, że Department nie dziedziczy po Company — zamiast tego Company ma atrybut departments, który jest listą zawierającą wiele Department obiektów. Podobnie Employee nie dziedziczy po Department. Zamiast tego Department ma atrybut employees — listę zawierającą wiele Employee obiektów.

Więcej przykładów

Kształt i trójkąt

W tym przypadku trójkąt jestkształtem (bardziej szczegółową wersją kształtu), więc wiemy, że klasa Triangle powinna dziedziczyć po klasie Shape.

class Shape():
    # stuff
class Triangle(Shape):
    # stuff

Użytkownik i Użytkownik Premium

Tutaj użytkownik premium jestużytkownikiem (bardziej specyficzną wersją użytkownika), więc wiemy, że PremiumUser powinien dziedziczyć po klasie User.

class User():
    # stuff
class PremiumUser(User):
    # stuff

Klasa i klasa matematyczna

W tym przypadku klasa odnosi się do zajęć, na które uczniowie chodzą, aby się czegoś nauczyć, a nie do koncepcji programowania. MathClass tutaj jestklasą (bardziej szczegółową wersją Class), więc wiemy, że MathClass powinna dziedziczyć po klasie Class.

class Class():
    # stuff
class MathClass(Class):
    # stuff

Klasa matematyczna i uczeń

Wiemy, że na lekcjach matematyki jest wielu uczniów. Obiekt MathClassma wielu Studentów i podobnie obiekt MathClass ma wiele obiektów Studentów. Jednak Student nie jestMathClass, więc nie ma tutaj żadnego dziedziczenia.

class MathClass():
    def __init__(self, stuff):
        self.stuff = stuff
        self.students = [] # list of Student objects
class Student():
    # stuff

Rodzic (człowiek) i dziecko (człowiek)

Tutaj klasa Parent odnosi się do ludzkiego rodzica (mama/tata), natomiast klasa Child odnosi się do ludzkiego dziecka. Co dziwne, tutaj nie ma miejsca na dziedziczenie! Ludzkie dziecko nie jestludzkim rodzicem, a Dziecko nie jest bardziej szczegółową wersją Rodzica. W związku z tym klasa Child nie dziedziczy po klasie Parent! (mimo że w prawdziwym życiu dziecko może odziedziczyć rzeczy po rodzicach)

# A long-winded example
class Parent():
    def __init__(self, name):
        self.name = name
        self.children = []
class Child():
    def __init__(self, name):
        self.name = name
        self.father = None
        self.mother = None
bob = Parent("bob")
mary = Parent("mary")
tom = Child("tom")
jerry = Child("jerry")
children = [tom, jerry]
bob.children = children
mary.children = children
tom.father = bob
tom.mother = mary
jerry.father = bob
jerry.mother = mary

Gang i członek gangu

Gang składa się z wielu członków gangu, ale członek gangu nie jest gangiem. Nie ma tu żadnego dziedzictwa.

class Gang():
    def __init__(self, stuff):
        self.stuff = stuff
        self.members = []
class GangMember():
    # stuff

Kilka ostatnich słów

Mam nadzieję, że te przykłady wyjaśnią, kiedy powinniśmy używać dziedziczenia, a kiedy nie — często musimy sprawdzić, czy istnieje związek między naszą rzekomą klasą podrzędną a klasą nadrzędną. Jeśli związek jest-a nie ma sensu:

  • Uczeń to klasa matematyczna
  • Dziecko jest rodzicem
  • Członek gangu to gang

Trzymajmy się z daleka od dziedziczenia.

Wniosek

Jeśli ten artykuł był wartościowy i chcesz wesprzeć mnie jako pisarza, rozważ zapisanie się do członkostwa Medium — kosztuje 5 USD miesięcznie i masz nieograniczony dostęp do historii na Medium. Jeśli zarejestrujesz się za pomocą mojego linku poniżej, otrzymam niewielką prowizję bez dodatkowych kosztów.

Zarejestruj się, korzystając z mojego linku, aby czytać nieograniczoną liczbę artykułów na Medium!

Jeśli ten artykuł był dla Ciebie niezwykle wartościowy, rozważ kupno mi kawy — każda drobna wpłata będzie dla Ciebie niezwykle cenna!

https://www.buymeacoffee.com/zlliu

Jeśli chcesz otrzymywać powiadomienia o każdej mojej publikacji, rozważ dołączenie do mojej listy e-mailowej.



Więcej treści na plainenglish.io. Zapisz się na nasz „bezpłatny cotygodniowy biuletyn”. Uzyskaj wyłączny dostęp do możliwości pisania i porad w naszym Discord społeczności.