调用方法由没有 super 的 mixin 实现
Calling methods implemend by mixins without super
我想要一个 mixin class,它期望具体的 class 定义特定的方法。类似于:
function BaseMixin(Base) {
class Mixin extends Base {
doSomething() {
this.onSomethingDone()
}
}
return Mixin
}
同时,我允许可选的 mixins 也可能声明这样的方法。最终结果是具体 class 和每个 mixin 都需要调用 super.onSomethingDone
并且因为应用 mixin 的顺序可以改变,所以它们还必须检查方法是否存在:
function SecondaryMixin(Base) {
class Mixin extends Base {
onSomethingDone() {
if (super.onSomethingDone)
super.onSomethingDone()
// stuff specific to SecondaryMixin
}
}
return Mixin
}
class ConcreteClass extends SecondaryMixin(BaseMixin(HTMLElement)) {
doSomething() {
if (super.onSomethingDone)
super.onSomethingDone()
// stuff specific to ConcreteClass
}
}
这很乏味且容易出错。相反,是否有可能只让实现者执行他们的 specific stuff
并在 BaseMixin
中以某种方式迭代并从所有应用的混合中调用 onSomethingDone
的所有实现?
function BaseMixin(Base) {
class Mixin extends Base {
doSomething() {
for (let onSomethingDone of getAllImplementationsThereof()) {
onSomethingDone()
}
}
}
}
您可以这样实施 getAllImplementations
:
function getAllImplementationsOf(cls, methodName) {
let fns = [];
cls = Object.getPrototypeOf(cls);
while (cls) {
if (cls.prototype && cls.prototype.hasOwnProperty(methodName))
fns.push(cls.prototype[methodName]);
cls = Object.getPrototypeOf(cls);
}
return fns;
}
//
function FirstMixin(Base) {
return class Mixin extends Base {
work() {
console.log('first')
}
}
}
function SecondMixin(Base) {
return class Mixin extends Base {
work() {
console.log('second')
}
}
}
class Base {
}
class ConcreteClass extends FirstMixin(SecondMixin(Base)) {
work() {
for (let fn of getAllImplementationsOf(this.constructor, 'work'))
fn.call(this);
console.log('done!')
}
}
new ConcreteClass().work();
话虽这么说,我不确定 extends
是否是实现混入的正确工具,正是因为这类问题。我宁愿研究代理。
我想要一个 mixin class,它期望具体的 class 定义特定的方法。类似于:
function BaseMixin(Base) {
class Mixin extends Base {
doSomething() {
this.onSomethingDone()
}
}
return Mixin
}
同时,我允许可选的 mixins 也可能声明这样的方法。最终结果是具体 class 和每个 mixin 都需要调用 super.onSomethingDone
并且因为应用 mixin 的顺序可以改变,所以它们还必须检查方法是否存在:
function SecondaryMixin(Base) {
class Mixin extends Base {
onSomethingDone() {
if (super.onSomethingDone)
super.onSomethingDone()
// stuff specific to SecondaryMixin
}
}
return Mixin
}
class ConcreteClass extends SecondaryMixin(BaseMixin(HTMLElement)) {
doSomething() {
if (super.onSomethingDone)
super.onSomethingDone()
// stuff specific to ConcreteClass
}
}
这很乏味且容易出错。相反,是否有可能只让实现者执行他们的 specific stuff
并在 BaseMixin
中以某种方式迭代并从所有应用的混合中调用 onSomethingDone
的所有实现?
function BaseMixin(Base) {
class Mixin extends Base {
doSomething() {
for (let onSomethingDone of getAllImplementationsThereof()) {
onSomethingDone()
}
}
}
}
您可以这样实施 getAllImplementations
:
function getAllImplementationsOf(cls, methodName) {
let fns = [];
cls = Object.getPrototypeOf(cls);
while (cls) {
if (cls.prototype && cls.prototype.hasOwnProperty(methodName))
fns.push(cls.prototype[methodName]);
cls = Object.getPrototypeOf(cls);
}
return fns;
}
//
function FirstMixin(Base) {
return class Mixin extends Base {
work() {
console.log('first')
}
}
}
function SecondMixin(Base) {
return class Mixin extends Base {
work() {
console.log('second')
}
}
}
class Base {
}
class ConcreteClass extends FirstMixin(SecondMixin(Base)) {
work() {
for (let fn of getAllImplementationsOf(this.constructor, 'work'))
fn.call(this);
console.log('done!')
}
}
new ConcreteClass().work();
话虽这么说,我不确定 extends
是否是实现混入的正确工具,正是因为这类问题。我宁愿研究代理。