Facebook提出Mixin的三个问题:
1.缺乏封装
2.隐式依赖
3.名称冲突
下面是Javascript的实现Mixin的类:
const Coloured = { // __Public Methods__ setColourRGB ({r, g, b}) { return this.colourCode = {r, g, b}; }, getColourRGB () { return this.colourCode; }, getColourHex () { return this.rgbToHex(this.colourCode); },
// __Private Methods__ componentToHex(c) { const hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex; }, rgbToHex({r, g, b}) { return "#" + this.componentToHex(r) + this.componentToHex(g) + this.componentToHex(b); } };
class Todo { constructor (name) { this.name = name || 'Untitled'; this.done = false; } title () { return name; } do () { this.done = true; return this; } undo () { this.done = false; return this; } }
Object.assign(Todo.prototype, Coloured);
|
注意到上述代码最后一行是将Todo和Coloured两个类Mixin混合。
这种Mixin混合显然破坏了Todo的封装性,因为将Coloured的行为混合编织进入了Todo,我们通过打开Todo代码是无法知道原来在运行时Todo还会依赖Coloured,产生了隐形依赖。
通过组合方式可以替代Mixn:
class Todo { constructor (name) { this.name = name || 'Untitled'; this.done = false; this[colouredObject] = Object.assign({}, Coloured); } do () { this.done = true; return this; } undo () { this.done = false; return this; } setColourRGB ({r, g, b}) { return this[colouredObject].setColourRGB({r, g, b}); } getColourRGB () { return this[colouredObject].getColourRGB(); } getColourHex () { return this[colouredObject].getColourHex(); } }
|
在上面代码中,我们实际将在外面的Object.assign类的混合动作从外面迁移到Todo这个类里面。其实搞这么复杂,不如老老实实地直接在Todo中直接引用Coloured,反而将两者依赖直观表达出来。
当然,原文在这个复杂道路上进行了疯狂探险:
From Mixins to Object Composition