Ориентация объекта на основе прототипа. Хороший, плохой, злой? - PullRequest
10 голосов
/ 22 декабря 2008

Я прихожу из классов по объектно-ориентированным языкам, и недавно я изучал эти модные динамические языки (JavaScript, Python и Lua), и мне нужны советы о том, как использовать ОО в этих языках. Было бы полезно узнать подводные камни и недостатки такого подхода, а также преимущества по сравнению с традиционными ОО.

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

Подводя итог, в чем заключаются хорошие, плохие и уродливые стороны такого подхода?

Ответы [ 5 ]

13 голосов
/ 22 декабря 2008

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

Я думаю, что людям больше всего нравится ("хороший"), что ОО на основе прототипа очень легкий и гибкий , предлагая очень высокое отношение мощности к весу .

Для советов о том, как использовать OO на основе прототипа, отличное место для начала - оригинальная статья Self на The Power of Simplicity .

7 голосов
/ 22 декабря 2008

Для сохранения пропускной способности здесь приведена ссылка на мой ответ на вопрос «Как я могу эмулировать« классы »в JavaScript? (Со сторонней библиотекой или без нее)» . Он содержит дополнительные ссылки, а также примеры.

Краткий ответ: сердце прототипа JavaScript OO - это делегирование. В этом стиле ООП разные объекты одного и того же «класса» могут делегировать обработку методов и свойств одному и тому же прототипу (обычно некоторому третьему объекту):

var foo = {
    property: 42,
    inc: function(){
        ++this.counter;
    },
    dec: function(){
        --this.counter;
    }
};
// Note: foo does not define `counter`.

Давайте создадим конструктор для объектов с foo в качестве прототипа. Фактически все необработанное будет передано в foo.

var Bar = function(){
    this.counter = 0;
};
Bar.prototype = foo;  // This is how we set up the delegation.

// Some people refer to Bar (a constructor function) as "class".

var bar = new Bar();

console.log(bar.counter);  // 0 --- Comes from bar itself
console.log(bar.property); // 42 --- Not defined in bar, comes from foo

bar.inc();  // Not defined in bar => delegated to foo
bar.inc();
bar.dec();  // Not defined in bar => delegated to foo
// Note: foo.inc() and foo.dec() are called but this === bar
// that is why bar is modified, not foo.

console.log(bar.counter);  // 1 --- Comes from bar itself

Давайте определим inc() непосредственно на панели:

bar.inc = function(){
    this.counter = 42;
};

bar.inc();  // Defined in bar => calling it directly.
            // foo.inc() is not even called.
console.log(bar.counter);  // 42 --- Comes from bar

Настройка цепочки одиночного наследования:

var Baz = function(){
    this.counter = 99;
};
Baz.protype = new Bar();

var baz = new Baz();

console.log(baz.counter); // 99
baz.inc();
console.log(baz.counter); // 100

console.log(baz instanceof Baz);    // true
console.log(baz instanceof Bar);    // true
console.log(baz instanceof Object); // true

Аккуратно, а?

2 голосов
/ 03 января 2009

Прежде чем беспокоиться о том, как эмулировать наследование на основе классов в JavaScript, быстро прочитайте Прототип наследования в JavaScript .

1 голос
/ 18 октября 2010

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

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

Таким образом, прототип означает гораздо более гибкую разработку модулей.

Конечно, совсем другое дело сказать, что ЛЕГКО разрабатывать без статической типизации. ИМО, это не так.

0 голосов
/ 22 декабря 2008

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

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

Реализация проста, но очень затрудняет эффективную проверку типов.

...