Должен наследование (неинтерфейсных типов) быть удаленным из языков программирования?

20 ответов

Я занесенный в блог об этом как дурацкая идея только что.

я не думаю, что это должно быть удалено, но я думаю, что классы должны быть изолированы по умолчанию к , препятствуют наследование, когда это не является соответствующим. Это - мощный инструмент для имения в наличии, но это похоже на цепную пилу - Вы действительно не хотите использовать его, если это не прекрасно инструмент для задания. Иначе Вы могли бы начать терять конечности.

потенциальные функции языка, такие как соединение-ins, которое помогло бы жить без, IMO.

20
ответ дан 1 December 2019 в 05:51
поделиться

Вопрос, "Должен наследование (неинтерфейсных типов) быть удаленным из языков программирования?"

я говорю, "Нет", поскольку он повредит адскую партию существующего кода.

, Что в стороне, необходимо использовать наследование кроме наследования интерфейсов? Я - преимущественно программист на C++, и я следую за строгой объектной моделью множественное наследование интерфейсов, сопровождаемых цепочкой единичного наследования классов . Реальные классы являются "секретом" компонента, и это - друзья, поэтому что продолжается существует бизнес ничтожеств.

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

Однако смесительная парадигма в значительной степени уникальна для C++. Без этого я ожидаю, что наследование очень привлекательно для прагматически настроенного программиста.

0
ответ дан 1 December 2019 в 05:51
поделиться

Если существует класс платформы, который делает почти точно, что Вы хотите, но конкретная функция его интерфейса выдает исключение NotSupported, или по некоторой другой причине Вы только хотите переопределить один метод, чтобы сделать что-то характерное для Вашей реализации, намного легче записать подкласс и переопределение, что один метод, а не пишет совершенно новый класс и передачи записи для каждого из других 27 методов в классе.

Точно так же Что относительно Java, например, то, где каждый объект наследовался Объекту и поэтому автоматически имеет реализации, равняется, хэш-код, и т.д. Я не должен повторно реализовывать их, и это "просто работает", когда я хочу использовать объект в качестве ключа в хеш-таблице. Я не должен писать передачу по умолчанию в Hashtable.hashcode(Object o) метод, который откровенно кажется, что перемещается далеко от объектной ориентации.

1
ответ дан 1 December 2019 в 05:51
поделиться

Наследование действительно необходимо? Зависит, под чем Вы подразумеваете "действительно". Вы могли вернуться к перфокартам или щелкающий переключателями в теории, но это - ужасный способ разработать программное обеспечение.

На процедурных языках, да, наследование классов является определенным благом. Это дает Вам способ изящно организовать Ваш код при определенных обстоятельствах. Это не должно злоупотребиться, поскольку любая другая функция не должна злоупотребиться.

, Например, возьмите случай digiarnie в этом потоке. Он использует интерфейсы почти для всего, которое так же плохо как (возможно хуже, чем) использующий большое наследование.

Некоторые его точки:

это помогает с тестированием и улучшает удобочитаемость

, Это не делает ни одной вещи. Вы никогда на самом деле тестируете интерфейс, Вы всегда тестируете объект, то есть, инстанцирование класса. И необходимость посмотреть на совершенно другой бит кода помогает Вам понять структуру класса? Я не думаю так.

Так же для глубоких иерархий наследования все же. Вы идеально хотите посмотреть в одном месте только.

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

Делегация является очень хорошей идеей и должна часто использоваться вместо наследования (например, Стратегическая модель - все о выполнении точно этого). Но интерфейсы имеют нуль, чтобы сделать с делегацией, потому что Вы не можете указать поведение вообще в интерфейсе.

также делает рефакторинг намного легче.

Ранняя приверженность интерфейсам обычно делает рефакторинг тяжелее, не легче, потому что существует затем больше мест для изменения. Злоупотребление наследования рано лучше (хорошо, менее плохо), чем злоупотребление интерфейсов, поскольку вытаскивающий классы делегата легче, если изменяемые классы не реализуют интерфейсов. И это довольно часто от тех делегатов, чем Вы получаете полезные интерфейсы.

, Таким образом, злоупотребление наследованием является плохой вещью. Злоупотребление интерфейсами является плохой вещью. И идеально, класс ничему ни не наследуется (кроме, возможно, "объекта" или эквивалентного языка), ни реализует любые интерфейсы. Но это не означает, что любая функция должна быть удалена из языка.

1
ответ дан 1 December 2019 в 05:51
поделиться

Вот хороший вид в теме:

IS-STRICTLY-EQUIVALENT-TO-A Reg Braithwaite

1
ответ дан 1 December 2019 в 05:51
поделиться

Нет, это не , нуждался , но это не означает, что не предоставляет общее преимущество, которое я думаю, более важно, чем волнение по поводу того, абсолютно ли это необходимо.

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

я нахожу наследование очень полезным те времена, которые я действительно хочу выразить, "-" отношения. Наследование, кажется, самые ясные средства выражения того намерения. Если я использовал делегацию ко всему повторному использованию реализации, я теряю ту выразительность.

это допускает злоупотребление? Конечно, это делает. Я часто вижу вопросы спросить, как разработчик может наследоваться классу, но скрыть метод, потому что тот метод не должен существовать на подклассе. Тот человек, очевидно, упускает суть наследования и должен быть указан к делегации вместо этого.

я не использую наследование, потому что оно необходимо, я использую его, потому что это иногда - лучший инструмент для задания.

1
ответ дан 1 December 2019 в 05:51
поделиться

Нет. Просто, потому что это не часто необходимо, не означает, что это никогда не необходимо. Как любой другой инструмент в инструментарии, это может (и быть, и будет), неправильно используемый. Однако это не означает, что это должно никогда использоваться. На самом деле, на некоторых языках (C++), нет такой вещи как 'интерфейс' на уровне языка, таким образом, без существенного изменения, Вы не могли запретить его.

2
ответ дан 1 December 2019 в 05:51
поделиться

Моя начальная буква думала, был, Вы являетесь сумасшедшими. Но после размышления об этом некоторое время я отчасти соглашаюсь с Вами. Я не говорю, удаляют Наследование классов полностью (абстрактные классы с частичной реализацией, например, могут быть полезными), но я часто наследовал (предназначенная игра слов) плохо написанный код OO со много наследованием классов уровня, которое ничего не добавило, кроме чрезмерного увеличения размера, к коду.

1
ответ дан 1 December 2019 в 05:51
поделиться

Обратите внимание, что наследование означает, что больше не возможно предоставить функциональность базового класса внедрением зависимости, чтобы к модульному тесту производный класс в изоляции его родителя.

Поэтому, если Вы смертельно серьезно относитесь к внедрению зависимости (который я не, но я действительно задаюсь вопросом, должен ли я быть), Вы не можете вытащить много использования из наследования так или иначе.

1
ответ дан 1 December 2019 в 05:51
поделиться

много времени, я предпочитаю базовый класс интерфейсу просто, потому что у меня есть некоторая стандартная функциональность. в C# я могу теперь использовать дополнительные методы для достижения этого, но он все еще не достигает того же самого для нескольких ситуаций.

2
ответ дан 1 December 2019 в 05:51
поделиться

Необходимый? Нет. Можно записать любую программу в C, например, который не имеет никакого вида наследования или объектов. Вы могли записать это в ассемблере, хотя это будет менее портативно. Вы могли записать это в Машине Тьюринга и эмулировать его. Кто-то разработал язык программирования точно с одной инструкцией (чему-то нравится, вычитают и переходят, если не нуль), и Вы могли бы записать свою программу в этом.

Так, если Вы собираетесь спросить, необходима ли данная функция языка (как наследование, или объекты, или рекурсия или функции), ответ нет. (Существуют исключения - необходимо смочь циклично выполнить и сделать вещи условно, хотя они не должны поддерживаться как явные понятия на языке.)

Поэтому я нахожу вопросы этого вида бесполезными.

Вопросы как, "Когда должен, мы используем наследование" или, "Когда не был должен мы" быть намного более полезными.

3
ответ дан 1 December 2019 в 05:51
поделиться

Весело проведите время реализовав ISystemObject на всех Ваших классах так, чтобы у Вас был доступ к ToString () и GetHashcode ().

Кроме того, удача с интерфейсом ISystemWebUIPage.

, Если Вам не нравится наследование, мое предложение состоит в том, чтобы прекратить использовать.NET все вместе. Существует слишком много сценариев, где это экономит время (см. DRY: не повторяйте себя).

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

я предпочитаю интерфейсы, но они не серебряная пуля.

5
ответ дан 1 December 2019 в 05:51
поделиться

Я предполагаю, что должен играть защитника дьявола. Если бы у нас не было наследования затем, то мы не смогли бы наследовать абстрактные классы, который использует шаблонный шаблон метода. Существует много примеров, где это используется в платформах, таких как.NET и Java. Поток в Java является таким примером:

// Alternative 1:
public class MyThread extends Thread {

    // Abstract method to implement from Thread
    // aka. "template method" (GoF design pattern)
    public void run() {
        // ...
    }
}

// Usage:
MyThread t = new MyThread();
t.start();

альтернатива, в моем значении, подробная , когда необходимо использовать его. Визуальная сложность помехи повышается. Это вызвано тем, что необходимо создать Поток, прежде чем можно будет на самом деле использовать его.

// Alternative 2:
public class MyThread implements Runnable {
    // Method to implement from Runnable:
    public void run() {
        // ...
    }
}

// Usage:
MyThread m = new MyThread();
Thread t = new Thread(m);
t.start();
// …or if you have a curious perversion towards one-liners
Thread t = new Thread(new MyThread());
t.start();

Наличие шляпы защитника моего дьявола прочь я предполагаю, что Вы могли утверждать, что усиление во второй реализации является внедрением зависимости или разделением проблем, которое помогает разрабатывающим тестируемым классам. В зависимости от Вашего определения того, что интерфейс (я услышал о по крайней мере трех) абстрактный класс мог рассматриваться как интерфейс.

3
ответ дан 1 December 2019 в 05:51
поделиться

Поскольку производство кодирует, я почти никогда не использую наследование. Я иду с использованием интерфейсов для всего (это помогает с тестированием и улучшает удобочитаемость, т.е. можно просто посмотреть на интерфейс, чтобы считать открытые методы и видеть то, что продолжается из-за хорошо названных методов и имен классов). В значительной степени единственное время, я использовал бы наследование, будет то, потому что сторонняя библиотека требует это. Используя интерфейсы, я получил бы тот же эффект, но я буду подражать наследованию при помощи 'делегации'.

Для меня, мало того, что это более читаемо, но и это является намного более тестируемым и также делает рефакторинг намного легче.

единственное время я могу думать об этом, я использовал бы наследование в тестировании, должен будет создать мой собственный определенный TestCases, используемый для дифференциации между типами тестов, которые я имею в своей системе.

, Таким образом, я, вероятно, не избавился бы от него, но я принимаю решение не использовать его как можно больше по упомянутым выше причинам.

4
ответ дан 1 December 2019 в 05:51
поделиться

Я желаю, чтобы языки обеспечили бы некоторые механизмы, чтобы помочь делегировать к членским переменным. Например, предположите интерфейс, у меня есть 10 методов, и класс C1 реализует этот интерфейс. Предположим, что я хочу реализовать класс C2, который является точно так же, как C1, но с методом m1 () переопределен. Не используя наследование, я сделал бы это следующим образом (в Java):

public class C2 implements I {
    private I c1;

    public C2() {
       c1 = new C1();
    }

    public void m1() {
        // This is the method C2 is overriding.
    }

    public void m2() {
        c1.m2();
    }

    public void m3() {
        c1.m3();
    }

    ...

    public void m10() {
        c1.m10();
    }
}

, Другими словами, я должен явно написать код для делегирования поведения методов m2.. m10 к членской переменной m1. Это - что-то вроде боли. Это также загромождает код так, чтобы было более трудно видеть реальную логику в классе C2. Это также означает, что каждый раз, когда новые методы добавляются для взаимодействия через интерфейс I, я должен явно добавить больше кода к C1 только для делегирования этих новых методов к C1.

я желаю, чтобы языки позволили бы мне говорить: C1 реализует I, но если C1 пропускает некоторый метод от меня, автоматически делегируйте к членской переменной c1. Это сократило бы размер C1 ко всего

public class C2 implements I(delegate to c1) {
    private I c1;

    public C2() {
       c1 = new C1();
    }

    public void m1() {
        // This is the method C2 is overriding.
    }
}

, Если бы языки позволили нам делать это, то было бы намного легче избежать использования наследования.

Вот статья блога, которую я записал об автоматической делегации.

6
ответ дан 1 December 2019 в 05:51
поделиться

Наследование может быть довольно полезным в ситуациях, где Ваш базовый класс имеет много методов с той же реализацией для каждого производного класса, для сохранения каждого производного класса от необходимости реализовать шаблонный код. Возьмите.NET Stream класс, например, который определяет следующие методы:

public virtual int Read(byte[] buffer, int index, int count)
{
}

public int ReadByte()
{
    // note: this is only an approximation to the real implementation
    var buffer = new byte[1];
    if (this.Read(buffer, 0, 1) == 1)
    {
        return buffer[0];
    }

    return -1;
}

, поскольку наследование доступно, базовый класс может реализовать ReadByte метод для всех реализаций без них имеющий необходимость волноваться об этом. Существует много других методов как это на классе, которые имеют значение по умолчанию или зафиксированные реализации. Таким образом в этом типе ситуации это - очень ценная вещь иметь, по сравнению с интерфейсом, где Ваши опции состоят в том, чтобы или заставить всех повторно реализовать все или создать StreamUtil класс типа, который они могут назвать (гогот!).

Для разъяснения с наследованием все я должен записать для создания DerivedStream, класс - что-то как:

public class DerivedStream : Stream
{
    public override int Read(byte[] buffer, int index, int count)
    {
        // my read implementation
    }
}

принимая во внимание, что, если мы используем интерфейсы и реализацию по умолчанию методов в StreamUtil, я должен написать набору больше кода:

public class DerivedStream : IStream
{
    public int Read(byte[] buffer, int index, int count)
    {
        // my read implementation
    }

    public int ReadByte()
    {
        return StreamUtil.ReadByte(this);
    }
}

}

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

10
ответ дан 1 December 2019 в 05:51
поделиться

Конечно, можно записать замечательные программы счастливо без объектов и наследования; функциональные программисты делают все это время. Но давайте не будем поспешными. Кто-либо заинтересовал этой темой, должен проверить слайды от приглашенной лекции Xavier Leroy приблизительно классы по сравнению с модулями в Объективном Caml. Xavier убирает красивое наложение задания, какое наследование преуспевает и не преуспевает в контексте различных видов эволюция программного обеспечения .

Все языки полны по Тьюрингу, поэтому конечно, наследование не необходимо. Но как аргумент в пользу значения наследования, я представляю синяя книга Smalltalk, особенно иерархия Набора и иерархия Числа . Я очень впечатлен, что квалифицированный специалист может добавить совершенно новый вид числа (или набор), не тревожа существующую систему.

я также напомню корреспонденту "приложения-приманки" для наследования: инструментарий GUI. Хорошо разработанный инструментарий (если можно найти один) делает очень, очень легким добавить новые виды графических виджетов взаимодействия.

сказавший все это, я думаю, что наследование имеет врожденные слабые места (Вашу логику программы мажут по большому набору классов), и что это должно использоваться редко и только квалифицированными профессионалами . Человек, получающий высшее образование со степенью бакалавра в области информатики едва, знает, что чему-либо о наследовании---такие люди нужно разрешить наследоваться другим классам в потребности, но никогда не должно писать код, которому наследовались другие программисты. То задание должно быть зарезервировано для основных программистов, которые действительно знают то, что они делают. И они должны сделать это неохотно!

Для интересного взятия при решении подобных проблем с помощью совершенно другого механизма, люди могли бы хотеть проверить классы .

типа Haskell
6
ответ дан 1 December 2019 в 05:51
поделиться

Нет. Иногда Вам нужно наследование. И в течение тех времен, где Вы не делаете - не используют его. Можно всегда "просто" использовать интерфейсы (на языках, которые имеют их), и автоматические обработки без работы данных как интерфейсы на тех языках, которые не имеют их. Но я не вижу оснований для удаления то, что иногда является необходимой функцией просто, потому что Вы чувствуете, что она не всегда необходима.

2
ответ дан 1 December 2019 в 05:51
поделиться

Наследование является одним из тех инструментов, которые могут использоваться и конечно могут быть неправильно использованы, но я думаю, что языки должны иметь больше изменений, прежде чем основанное на классах наследование могло быть удалено.

Позволяют нам взять мой мир в данный момент, который является главным образом разработкой C#.

, Чтобы Microsoft устранила основанное на классах наследование, они должны были бы создать в намного более сильной поддержке обработки интерфейсов. Вещи как агрегирование, где я должен добавить много шаблонного кода только для обеспечения электричеством интерфейса к внутреннему объекту. Это действительно должно быть сделано так или иначе, но было бы требованием в таком случае.

, Другими словами, следующий код:

public interface IPerson { ... }
public interface IEmployee : IPerson { ... }
public class Employee : IEmployee
{
    private Person _Person;
    ...

    public String FirstName
    {
        get { return _Person.FirstName; }
        set { _Person.FirstName = value; }
    }
}

Это должно было бы в основном быть намного короче, иначе у меня будет много этих свойств только, чтобы заставить мой класс подражать достаточно хорошему человеку, что-то вроде этого:

public class Employee : IEmployee
{
    private Person _Person implements IPerson;
    ...
}

это могло автосоздать необходимый код вместо меня имеющий необходимость записать это. Просто возврат внутренней ссылки, если бы я бросил свой объект IPerson, сделал бы отрицательный результат.

, Таким образом, вещи должны были бы лучше поддерживаться, прежде чем основанное на классах наследование могло быть исключено из рассмотрения.

кроме того, Вы удалили бы вещи как видимость. Интерфейс действительно просто имеет две настройки видимости: Там, и нет. В некоторых случаях Вы были бы, или таким образом, я думаю, вынужденный выставить больше Ваших внутренних данных именно так, что кто-то еще может более легко использовать Ваш класс.

Для основанного на классах наследования, можно обычно выставлять некоторые точки доступа, которые может использовать потомок, но вне кода не может, и необходимо было бы обычно просто удалять те точки доступа или заставлять их открыться всем. Не уверенный мне нравится любая альтернатива.

Мой самый большой вопрос был бы, какова конкретно точка удаления такой функциональности будет, даже если план был бы к, как пример, создал бы D#, новый язык, как C#, но без основанного на классах наследования. Другими словами, даже если бы Вы планируете создание совершенно нового языка, я все еще не совсем уверен, какова конечная цель была бы.

цель удалить что-то, чем можно злоупотребить если не в правых руках? Если так, у меня есть список, миля жаждет различных языков программирования, что я был бы действительно , любят видеть адреса сначала.

Наверху того списка: с [1 117] ключевое слово в Delphi. То ключевое слово точно так же, как не стреляет себе в ногу, оно похоже на компилятор, покупает ружье, прибывает в Ваш дом и прицеливается для Вас.

Лично мне нравится основанное на классах наследование. Несомненно, можно записать себя в угол. Но мы можем все сделать это. Удалите основанное на классах наследование, я просто найду новый способ выстрелить себе в ногу с.

Теперь, куда я помещал то ружье...

5
ответ дан 1 December 2019 в 05:51
поделиться

Я считаю, что лучшим механизмом для повторного использования кода, который иногда достигается посредством наследования, являются черты . По этой ссылке (pdf) вы найдете подробное обсуждение этого вопроса, включая различие между чертами и миксинами, а также почему предпочтение отдается чертам.

Есть некоторые исследования, которые вводят черты в C # (pdf) .

Perl имеет черты Moose :: Roles . Черты Scala похожи на примеси , как в Ruby .

1
ответ дан 1 December 2019 в 05:51
поделиться