Классическое Vs прототипное наследование - PullRequest
18 голосов
/ 20 сентября 2009

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

Ответы [ 3 ]

23 голосов
/ 02 августа 2013

Существует множество проблем с классическим наследованием, которых не существует с наследованием прототипов, таких как:

Классическое наследство

Герметичная муфта . Наследование - самая прочная связь, доступная в дизайне OO. У классов потомков есть глубокие знания о классах их предков.

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

Многократное наследование является сложным . Часто желательно наследовать от более чем одного родителя. Этот процесс чрезмерно сложен, и его реализация несовместима с процессом одиночного наследования, что затрудняет его чтение и понимание.

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

Проблема Гориллы / Банана . Часто есть части родительского объекта, которые вы не хотите наследовать. Подклассы позволяют переопределять свойства родительского объекта, но не позволяют выбирать, какие свойства вы хотите наследовать.

Прототип наследования

Чтобы понять, как наследование прототипа решает эти проблемы, вы должны сначала понять, что существует два разных типа наследования прототипа. JavaScript поддерживает оба:

Делегирование . Если свойство не найдено в экземпляре, оно ищется в прототипе экземпляра. Это позволяет вам совместно использовать методы среди многих экземпляров, предоставляя вам шаблон flyweight бесплатно .

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

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

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

Некоторые преимущества наследования прототипа:

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

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

Тривиальное множественное наследование . Наследование от нескольких предков так же просто, как объединение свойств из нескольких прототипов с использованием конкатенации для формирования нового объекта или нового делегата для нового объекта.

Гибкая архитектура . Поскольку вы можете выборочно наследовать с помощью прототипа OO, вам не нужно беспокоиться о проблеме «неправильного дизайна». Новый класс может наследовать любую комбинацию свойств от любой комбинации исходных объектов. Из-за простоты выравнивания иерархии, изменение в одном месте не обязательно вызывает рябь в длинной цепочке объектов-потомков.

Горилл больше нет . Селективное наследование устраняет проблему бананов горилл.

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

8 голосов
/ 20 сентября 2009

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

Широкополосное обсуждение подходов к моделированию доступно здесь: http://steve -yegge.blogspot.com / 2008/10 / universal-design-pattern.html

4 голосов
/ 20 сентября 2009

Поскольку Javascript не поддерживает «классическое» наследование, как многие понимают (и вы не дали никаких ссылок на то, что вы читали), я предполагаю, что вы имеете в виду наследование, обрабатываемое так: -

 function base() {
    var myVar;
    this.someBaseFunc = function() { }
 }


 function derived() {
    base.call(this);
    var someOtherVar;
    this.SomeOtherFunc = function() { }
 }

Мое общее правило:

  • Если классы сложны, а экземпляры немногочисленны, используйте «классический» подход. Это позволяет классам публично раскрывать только те функции, которые должны быть обнародованы.
  • Если класс прост и во многих случаях используется прототипный подход. Это ограничивает накладные расходы на определение и хранение ссылок на функции снова и снова при создании экземпляров.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...