从Mixin到对象组合

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