Ответ 1
Ребенок не может родиться до родительского "существования".
В Java и других языках OOP super() должен быть вызван до. Создан текущий объект.
Это логично, потому что child cannot be born before parent
.
TypeScript 2 теперь могут иметь инструкции перед super
, если они не используются для this
.
Это была одна из частей ответа, почему this
нельзя использовать перед ужином.
Методы переопределения детей, которые используются в конструкторе, должны существовать исключительно в "родительских" ресурсах.
Следующая часть, на которую накладываются вопросы, заключается в том, что объект parent
фактически вызывает переопределение своих дочерних элементов assemble
в то же время, когда этот ребенок не создается вообще.
Кажется странным, потому что дети не создаются, но родительский конструктор вызывает метод children... И кажется неестественным, как нерожденный ребенок говорит "папа".
См. подобное сообщение об этой проблеме.
Но это неправильный способ думать так. Переопределения от детей, которые будут использоваться в конструкторе, существуют только для изменения того, как будет создан ваш ребенок.
Переопределение метода, используемое в родительском конструкторе, должно указывать, как должен обрабатываться ваш экземпляр. Из тех ресурсов, которые доступны для родителя, но не из ресурса, который имеет ваш несуществующий экземпляр.
Утиные типизирующие прототипы и наследование...
Наследование в прототипах обычно достигается путем компоновки нового прототипа с такими функциональными возможностями extend
.
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
С этой точки зрения нет "детей" и "родителей" как таковых, но есть "множества", вроде. Набор может быть расширен другим набором только тогда, когда он уже существует. Это приводит нас к:
Дизайн сверху вниз и снизу вверх.
Прототипы и утиная печать работают в снизу вверх. ООП в дизайне сверху вниз.
Как обойти эту странную ситуацию в этом случае?
Просто не надо! Используйте силу идей ООП, изучая их и внедряя! Здесь, как добиться успеха:
- Состав над наследованием, переосмыслите дизайн кода. Разделите базовый класс на интерфейс и класс, экземпляр которого вы можете передать конструктору "дочернего" класса, и составить желаемый экземпляр, выполнив объявленный интерфейс.
-
Используйте static, но имейте в виду, что это изменение будет одинаковым для всех экземпляров вашего объекта.
Это нормально, если вы используете это только для инъекций зависимостей
-
Умное переопределение.
Не используйте дополнительные ресурсы из экземпляра sibling ( "child" ) и создайте собственный дополнительный метод, который будет вызываться из конструктора.
Пример ниже (обратите внимание, что это не нарушает LSP, потому что только
__assembled
устанавливается только один раз в конструкторе):abstract class Base { constructor(view: string) { this._assemble(); } protected _assemble(): void { console.log("abstract assembling for all base classes"); } } class Example extends Base { private __assembled: boolean = false; constructor(view: string, private helper: Function) { super(view); this._assemble_helper(); this.__assembled = true; } public tryMe(): void { this._assemble(); } protected _assemble(): void { super._assemble(); // removed from here all extra resources // but run them when u need to assemble them again. if (this.__assembled) { this._assemble_helper(); } } protected _assemble_helper(): void { // at first run this.helper will be undefined! console.log("example assembling", this.helper); } } let e = new Example("hoho", function () { return; }) console.log("So now i will try to reassemble..."); e.tryMe();
Вот результат с препарированным ES5:
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var Base = (function () {
function Base(view) {
this._assemble();
}
Base.prototype._assemble = function () {
console.log("abstract assembling for all base classes");
};
return Base;
}());
var Example = (function (_super) {
__extends(Example, _super);
function Example(view, helper) {
var _this = _super.call(this, view) || this;
_this.helper = helper;
_this.__assembled = false;
_this._assemble_helper();
_this.__assembled = true;
return _this;
}
Example.prototype.tryMe = function () {
this._assemble();
};
Example.prototype._assemble = function () {
_super.prototype._assemble.call(this);
// removed from here all extra resources
// but run them when u need to assemble them again.
if (this.__assembled) {
this._assemble_helper();
}
};
Example.prototype._assemble_helper = function () {
// at first run this.helper will be undefined!
console.log("example assembling", this.helper);
};
return Example;
}(Base));
var e = new Example("hoho", function () { return; });
console.log("So now i will try to reassemble...");
e.tryMe();