Существуют ли ОО-языки без наследования?

22

Во время сегодняшнего обзора кода мой коллега сказал что-то интересное:

prototypeполезно только тогда, когда вам нужно наследование - и когда наследование когда-либо является хорошей идеей ?

Я подумал об этом и понял, что обычно использую наследование, чтобы обойти код, который изначально был плохо спроектирован. Современный ОО-стиль предпочитает композицию, а не наследование, но я не знаю ни одного языка, который принимал бы это близко к сердцу и фактически применял его.

Существуют ли универсальные языки программирования с классами, объектами, методами, интерфейсами и т. Д., Которые запрещают наследование на основе классов? (Если такая идея не имеет смысла, почему бы и нет?)

Бенджамин Ходжсон
источник
7
Ваш коллега сбил вас с пути. Это prototypeтакже полезно, когда у вас есть открытые методы и свойства, которые должны быть общими для всех экземпляров. Это также полезно , потому что позволяет правильно использовать instanceofоператор в JavaScript: if (foo instanceof Foo) { ....
Грег Бургхардт
2
Я думаю, что мы должны сделать различие между наследованием типа, состояния и поведения. Предпочтение композиции очень распространено в сообществе Java, но в то же время наследование (и даже множественное наследование) типов широко используется и поощряется ... и реализуется с использованием implementsключевого слова и интерфейсов (в отличие от наследования состояний и поведение, введенное с использованием extendsключевого слова в классах, содержащих любую реализацию).
toniedzwiedz
6
Предпочтение композиции не означает, что отказ от наследства - хорошая идея.
Калеб
5
смотрите Java без наследования реализации : «Google go - это пример языка, который избавляется от наследования реализации, будучи ООП ...»
gnat
1
@GregBurghardt То же самое можно сделать с помощью фабричной функции, которая возвращает объект, содержащий функции (хранение личных данных в замыкании). new, thisИ prototypeвсе слишком много минного поля для общего пользования ИМО.
Бенджамин Ходжсон

Ответы:

18

Оставляя в стороне вопрос об определении объектно-ориентированного программирования, вопрос становится одним из "существуют ли языки, которые используют только композицию и не имеют инструментов для наследования?"

Ответ на это довольно просто «да». На самом деле, нет никакого способа сделать наследование, как думают классически. Один может внедренный объект в другом объекте и продлить этот объект. Из объекта Desoriented Language ( github mirror ):

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()
}

У вас есть личная структура с именем, которое является строкой. У него есть публичная функция Intro, которая возвращает имя. В структуре Woman также есть функция Intro, которая обращается к встроенной в нее стойке. И поэтому можно реализовать намерения наследования, используя только композицию.

Подробнее об этом можно узнать из учебников GoLang: Наследование и создание подклассов в Go - или его близкое сходство .

Так что да, можно иметь ОО-язык без наследования, и он существует.

В Go это называется встраиванием и дает вложенным структурам возможность доступа к встроенным полям и функциям, как если бы они были у них тоже - но это не подкласс. Философию дизайна можно найти в Go FAQ: Почему нет наследования типов?


источник
Можно также прокомментировать использование typedefи structв C ...
cwallenpoole
@cwallenpoole, там действительно есть похожие идеи, хотя я бы не стал называть C объектно-ориентированным языком.
Не знаю. Я признаю тот факт, что вы не можете создавать объекты с прикрепленными функциями, и это работает против него, но без наследования ООП теряет большую часть своего вкуса.
cwallenpoole
@cwallenpoole, и мы начинаем определять, что такое наследование и объектная ориентация. Но это возможно, его просто другой способ думать о проблеме. Дело в том, что наследование - это способ, которым большинство программистов на C ++ и Java думают о расширении ... но есть и другие модели. Расширение без наследования: 1 , 2 , 3 - хорошие чтения.
В данный момент ссылка на «Object Desoriented Language» застряла в цикле перенаправления, но я нашел статью здесь: github.com/nu7hatch/areyoufuckingcoding.me/blob/master/content/… . Благодарность!
Мэтт Браун
7

Существуют ли универсальные языки программирования с классами, объектами, методами, интерфейсами и т. Д., Которые запрещают наследование на основе классов?

Это очень похоже на описание VBA - Visual Basic для приложений, встроенного в Microsoft Office и других хостов с поддержкой VBA (например, AutoCAD, Sage 300 ERP и т. Д.) Или даже VB6. «A» в «Basic» означает «универсальный», так что есть часть «общего назначения».

VB6 / VBA имеет классы (и, следовательно, объекты), методы и интерфейсы - вы можете определить ISomethingинтерфейс в модуле класса следующим образом:

Option Explicit

Public Sub DoSomething()
End Sub

И затем есть другой класс, который делает это:

Option Explicit
Implements ISomething

Private Sub ISomething_DoSomething()
    'implementation here
End Sub

К такому классу, не предоставляющему общедоступных членов, можно было получить доступ только через его ISomethingинтерфейс - и вполне могли существовать десятки различных реализаций ISomething, поэтому код ООП VBA вполне способен к полиморфизму, и он совершенно законен для данного класса. реализовать несколько интерфейсов тоже.

Однако VB6 / VBA не разрешает наследование классов , поэтому вы не можете наследовать реализацию от другого типа, только от его интерфейса. Теперь, является ли это несчастным случаем, недостатком проекта, ударом гения или огромным безобразным упущением, открыт для дебатов; не ясно, принимает ли VB6 / VBA это близко к сердцу , но это определенно усиливает это.

Если Go не выполняет наследование классов и, тем не менее, является языком ООП , то я не понимаю, почему VB6 / VBA также нельзя считать языком ООП.</PreemptiveResponseToVBAHatersThatWillSayItIsNotAnOOPLanguage>

Матье Гиндон
источник
1
Честно говоря, ОП спросила о современных языках. =;) -
RubberDuck
@RubberDuck # ожог!
Матье Гиндон
0

Вы можете заставить компилятор принудительно применять выборочное наследование с помощью частного / защищенного и современного использования методов "PImpl" или "Частная реализация".

Многие API предоставляют только те компоненты, которые вы бы хотели, чтобы пользователь унаследовал, а остальные скрывают в отдельном классе реализации. Таким образом, вы могли бы написать классы, чьи общедоступные интерфейсы, на самом деле, не наследуются, могут использоваться только через композицию объектов и принудительно компилируются Это часто хорошая практика, когда он использует компилятор для реализации намерения программного обеспечения.

Быстрый поиск закрытых функций-членов в javascript показывает, что существует аналогичный принцип, хотя любой может увидеть ваш код, если сможет его использовать: http://www.crockford.com/javascript/private.html

Руан Кайман
источник