Зачем использовать наследование объектов вместо миксинов - PullRequest
5 голосов
/ 17 сентября 2011

суть

Каковы причины отдавать предпочтение наследованию перед миксинами

Учитывая следующий пример псевдокода:

class Employee

class FullTimeEmployee inherits Employee

class PartTimeEmployee inherits Employee

// versus

class Employee

class WorksPartTime

class WorksFullTime

class FullTimeEmployee includes Employee, WorksFullTime
class PartTimeEmployee includes Employee, WorksPartTime

Если мыесли бы использовать наследование для создания объектов, отношения классов были бы видны как дерево, где, как и в случае с миксинами, отношения классов были бы видны как плоский список.1014 * позволяет использовать миксины с невербальным синтаксисом

позволяет нам трактовать FullTimeEmployee как объект Employee и FullTime прозрачно.

зачем нам строитьнаши классовые отношения как деревья (наследование) вместо плоских списков (композиция)?

Пример дерева и списка.

class Person

class Employee inherits Person

class FullTimeEmployee inherits Employee

//                      -> FullTimeEmployee
//  Person -> Employee
//                      -> PartTimeEmployee

class Person

class Employee includes Person

class FullTime

class FullTimeEmployee includes FullTime, Employee

//
// FullTimeEmployee = (FullTime, Employee, Person)
//

Ответы [ 3 ]

3 голосов
/ 17 сентября 2011

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

Если это все верно, то в некотором смысле они эквивалентны, и вопрос не имеет смысла - ни один не лучше, чем другие, потому что они эквивалентны по функциональности.

С точки зрения человеческого понимания, я думаю, что большинство людей думают о наследовании с точки зрения отношения isA и смешивают с точки зрения украшения чего-либо с помощью функциональности.

Если вы можете наследовать только от одного «класса», то, очевидно, миксины - это способ получить множественное наследование.

РЕДАКТИРОВАТЬ - основываясь на ваших комментариях, которые хороши, я бы сказал, детали гипотетического языка имеют значение. Я признаю, что я основываю свой ответ на Sproutcore, который является фреймворком Javascript, который формализовал поддержку как миксинов, так и наследования. В СЦ вы можете сделать

App.MyObject = SC.Object.extend({
  prop: 'prop',
  func: function(){
})

, который делает то, что вы ожидаете, он помещает prop и func в прототип MyObject, создавая "класс", который может иметь подклассы. Вы также можете сделать

App.MyObject = SC.Object.extend(App.OtherObject, {
   // stuff
})

, который делает множественное наследование. Тогда вы можете получить что-то вроде

CommonFunctionality = {
    // some methods
};

App.mixin(CommonFunctionality);

, который применил бы CommonFunctionality к 1023 *. Если бы приложение было пространством имен (то есть a {}), методы CommonFunctionality были бы применены к этому литералу объекта. Если бы это имело смысл, вы могли бы также применить CommonFunctionality к «классу», и его методы были бы в прототипе. Если вы посмотрите в источнике, вы увидите

SC.extend = SC.mixin ;

Так что в SC нет абсолютно никакой разницы, потому что это один и тот же метод.

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

0 голосов
/ 29 января 2014

Вы должны использовать, когда появляется необходимость. Если у вас большой класс с 1000 строками, и вы обнаруживаете, что повторяете одни и те же вещи в нескольких классах, вы можете инкапсулировать некоторую логику в базовый класс, а другую - в миксины. Каждый миксин имеет ограниченный контекст, они могут знать о большем, чем должны, но они сосредоточены только на определенной задаче. Поэтому очень модульные. Ну, лучший пример, который я могу вам дать, это Актер для игры , который имеет наследование для некоторых базовых вещей, но использует mixins / плагины для общей функциональности , Совместная функциональность может быть (непосредственно из исходного кода!):

var plugins = {
    SingleVisualEntity : SingleVisualEntity,
    JumpBehaviour      : JumpBehaviour,
    WeaponBehaviour    : WeaponBehaviour,
    RadarBehaviour     : RadarBehaviour,
    EnergyGatherer     : EnergyGatherer,
    LifeBarPlugin      : LifeBarPlugin,
    SelectionPlugin    : SelectionPlugin,
    UpgradePlugin      : UpgradePlugin,
    BrainPlugin        : BrainPlugin,
    PlanetObjectPlugin : PlanetObjectPlugin,
}

Изначально это был класс с +1000 строками.

0 голосов
/ 17 сентября 2011

При проектировании мы стараемся максимально симулировать реальность.

Учитывая принципы is a и has a, FullTimeEmployee is an Employee, у которого есть дополнительная (дополнительная) функция, и не какая-то новая вещь, которая has an Employee рядом с чем-то, называемым FullTime, и и так далее для PartTimeEmployee.

...