Czy są jakieś języki OO bez dziedziczenia?

22

Podczas dzisiejszego przeglądu kodu mój kolega powiedział coś interesującego:

prototypeprzydaje się tylko wtedy, gdy potrzebujesz dziedziczenia - a kiedy dziedziczenie jest zawsze dobrym pomysłem ?

Pomyślałem o tym i zdałem sobie sprawę, że zwykle używam dziedziczenia, aby obejść kod, który został źle zaprojektowany. Współczesny styl OO woli kompozycję niż dziedziczenie, ale nie znam żadnych języków, które wzięłyby to sobie do serca i faktycznie je egzekwowały .

Czy istnieją języki programowania ogólnego przeznaczenia z klasami, obiektami, metodami, interfejsami itp., Które nie pozwalają na dziedziczenie oparte na klasach? (Jeśli taki pomysł nie ma sensu, dlaczego nie?)

Benjamin Hodgson
źródło
7
Twój kolega sprowadził cię na manowce. Jest prototypeto również przydatne, gdy masz publiczne metody i właściwości, które powinny być współużytkowane między instancjami. Jest to także przydatne, ponieważ pozwala właściwie używać instanceofoperatora w JavaScript: if (foo instanceof Foo) { ....
Greg Burghardt
2
Myślę, że powinniśmy rozróżnić dziedziczenie typu, stanu i zachowania. Preferowana kompozycja jest bardzo powszechna w społeczności Java, ale jednocześnie dziedziczenie (a nawet wielokrotne dziedziczenie) typów jest szeroko stosowane i zalecane ... i realizowane przy użyciu implementssłowa kluczowego i interfejsów (w przeciwieństwie do dziedziczenia stanu i zachowanie wprowadzone za pomocą extendssłowa kluczowego w klasach zawierających dowolną implementację).
toniedzwiedz
6
Preferowanie kompozycji nie oznacza całkowitego porzucenia dziedziczenia, to dobry pomysł.
Caleb
5
zobacz Java bez dziedziczenia implementacji : „Google go to przykład języka, który eliminuje dziedziczenie implementacji będąc OOP ...”
gnat
1
@GregBurghardt To samo można osiągnąć za pomocą funkcji fabrycznej, która zwraca obiekt zawierający funkcje (przechowywanie prywatnych danych w zamknięciu). new, thisI prototypesą zbyt duże pole minowe do wspólnego użytku IMO.
Benjamin Hodgson,

Odpowiedzi:

18

Pomijając kwestię definicji programowania obiektowego, pytanie staje się jednym z „czy istnieją języki, które używają wyłącznie kompozycji i nie mają narzędzi do dziedziczenia?”

Odpowiedź na to pytanie jest po prostu „tak”. W praktyce nie ma sposobu na dziedziczenie, o czym klasycznie się myśli. One mogą osadzony obiekt w innym obiekcie i przedłużyć ten obiekt. Z Object Desoriented Language ( mirror github ):

type Person struct {
        Name string
}

func (p *Person) Intro() string {
        return p.Name
}

type Woman struct {
        Person
}

func (w *Woman) Intro() string {
        return "Mrs. " + w.Person.Intro()
}

Masz strukturę osoby o nazwie, która jest łańcuchem. Ma funkcję publiczną o nazwie Intro, która zwraca nazwę. Struktura Woman ma również funkcję Intro, która ma dostęp do osadzonej w niej kolumny. I tak można spełnić zamiary dziedziczenia, używając tylko kompozycji.

Więcej na ten temat można znaleźć w Samouczkach GoLang: Dziedziczenie i podklasowanie w Go - lub jego zbliżonym podobieństwie .

Tak więc możliwe jest posiadanie języka OO bez dziedziczenia, a taki istnieje.

Wewnątrz go jest to nazywane osadzaniem i daje otaczającym strukturom możliwość dostępu do osadzonych pól i funkcji tak, jakby miały je również - ale nie jest to podklasa. Filozofię projektowania można znaleźć w Go FAQ: Dlaczego nie ma dziedziczenia typu?


źródło
Można również komentować użycie typedefiw structC ...
cwallenpoole
@ cwallenpoole są tam rzeczywiście podobne pomysły, choć wahałbym się nazwać C językiem obiektowym.
Nie wiem. Przyznaję, że nie można tworzyć obiektów z dołączonymi funkcjami, działa przeciwko niemu, ale bez dziedziczenia OOP traci wiele ze swojego smaku.
cwallenpoole
@cwallenpoole i zaczynamy definiować dziedziczenie i orientację obiektową. Ale jest to możliwe, to po prostu inny sposób myślenia o problemie. Chodzi o to, że dziedziczenie jest sposobem, w jaki większość programistów C ++ i Java myśli o rozszerzeniu ... ale są też inne modele. Rozszerzenie bez dziedziczenia: 1 , 2 , 3 to dobre odczyty.
Link do „Object Desoriented Language” utknął w tej chwili w pętli przekierowań, ale znalazłem ten artykuł tutaj: github.com/nu7hatch/areyoufuckingcoding.me/blob/master/content/… . Dzięki!
Matt Browne,
7

Czy istnieją języki programowania ogólnego przeznaczenia z klasami, obiektami, metodami, interfejsami itp., Które nie pozwalają na dziedziczenie oparte na klasach?

Odczytuje to bardzo podobnie do opisu VBA - Visual Basic for Applications, osadzonego w Microsoft Office i innych hostach obsługujących VBA (np. AutoCAD, Sage 300 ERP itp.), A nawet VB6. „A” „Basic” i tak oznacza „Uniwersalny”, więc jest część „ogólnego przeznaczenia”.

VB6 / VBA ma klasy (a zatem obiekty), metody i interfejsy - możesz zdefiniować ISomethinginterfejs w module klasy takim jak ten:

Option Explicit

Public Sub DoSomething()
End Sub

A potem mają inną klasę, która to robi:

Option Explicit
Implements ISomething

Private Sub ISomething_DoSomething()
    'implementation here
End Sub

Do takiej klasy, nie ujawniającej żadnych członków publicznych, można było kiedykolwiek uzyskać dostęp tylko poprzez jej ISomethinginterfejs - i może istnieć dziesiątki różnych implementacji ISomething, więc kod OOP VBA jest doskonale zdolny do polimorfizmu i jest całkowicie legalny dla danej klasy do implementacji wielu interfejsów.

VB6 / VBA nie pozwala jednak na dziedziczenie klas , więc nie można dziedziczyć implementacji z innego typu, tylko z interfejsu. Niezależnie od tego, czy jest to wypadek, wada projektowa, genialny pomysł, czy ogromny brzydki nadzór, jest przedmiotem dyskusji; nie jest jasne, czy VB6 / VBA bierze to sobie do serca , ale zdecydowanie to egzekwuje .

Jeśli Go nie wykonuje dziedziczenia klas i mimo to jest językiem OOP , to nie rozumiem, dlaczego VB6 / VBA nie może być również uważany za język OOP.</PreemptiveResponseToVBAHatersThatWillSayItIsNotAnOOPLanguage>

Mathieu Guindon
źródło
1
Aby być uczciwym, OP zapytał o współczesne języki. =;) -
RubberDuck
@RubberDuck #burn!
Mathieu Guindon
0

Możesz zmusić kompilator do egzekwowania dziedziczenia selektywnego poprzez zastosowanie prywatnych / chronionych i poprzez nowoczesne wykorzystanie technik „PImpl” lub „Private Implementation”.

Wiele interfejsów API udostępnia tylko te komponenty, które użytkownik chciałby odziedziczyć, a resztę ukrywa w osobnej klasie implementacji. Można więc pisać klasy, których publiczne interfejsy są w rzeczywistości nie do odziedziczenia, możliwe do użycia tylko poprzez kompozycję obiektów i wymuszone przez kompilator. Jest to często dobra praktyka, gdy używa kompilatora do wymuszania zamiarów oprogramowania.

Szybkie wyszukiwanie funkcji prywatnych członków w javascript pokazuje, że istnieje podobna zasada, chociaż każdy może zobaczyć twój kod, jeśli może go użyć: http://www.crockford.com/javascript/private.html

Ruan Caiman
źródło