從Mixin到物件組合

banq發表於2016-07-23

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);
<p>

注意到上述程式碼最後一行是將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();
  }
}
<p>

在上面程式碼中,我們實際將在外面的Object.assign類的混合動作從外面遷移到Todo這個類裡面。

其實搞這麼複雜,不如老老實實地直接在Todo中直接引用Coloured,反而將兩者依賴直觀表達出來。

當然,原文在這個複雜道路上進行了瘋狂探險:

From Mixins to Object Composition

相關文章