一.Mixin パターンとコードの再利用
最も一般的なコードの再利用方法は継承ですが、サブクラスはスーパークラスのすべてのプロパティを取得するため、余分なプロパティを継承してしまう可能性があります。1 つの解決策は、スーパークラスのプロパティを複数のインターフェースクラスに分割し、サブクラスがこれらのインターフェースクラスから継承が必要なプロパティを「自分で取得」するようにすることですが、Java のインターフェースは完全に抽象的であり(実装を含まない)、コードの再利用を実現できません。コンポジションを使用するとこの問題を緩和できますが、根本的に解決することはできず、コンポジションは各依存オブジェクトへの参照を保持し、その基础上で再度カプセル化してインターフェースを提供する必要があるため、複雑性が増します
既存のオブジェクトの一部のプロパティのみを再利用したい場合、Mixin パターンは間違いなく最良の選択です。複雑なクラス階層関係を全く考慮する必要がないためです。既存の継承メカニズム基础上で、部分的な継承(スーパークラスから必要な一部のプロパティのみを取得)と多重継承(複数のスーパークラスからプロパティを取得) を実現できることを望んでいますが、Mixin パターンはまさにこれを行います
二.Mixin パターンの実装
Mixin パターンの実装は実際にはプロパティのコピーの一種です。サンプルコードは以下の通り:
// 部品倉庫 1
function Moveable() {}
Moveable.prototype.walk = function() {
console.log('walked slowly');
}
Moveable.prototype.run = function() {
console.log('ran quickly');
}
Moveable.prototype.jump = function() {
// ...
}
// 部品倉庫 2
function Souled() {}
Souled.prototype.smile = function(age) {
console.log('smiled as ' + age + ' year\'s old kid');
}
// 部品倉庫 3
// mixin
function augment(sub, sup) {
// 継承所有属性
if (arguments.length === 2) {
for(var attr in sup.prototype) {
sub.prototype[attr] = sup.prototype[attr];
}
}
// 継承部分属性
else if(arguments.length > 2) {
for (var i = 2; i < arguments.length; i++) {
sub.prototype[arguments[i]] = sup.prototype[arguments[i]];
}
}
else {
// do nothing
}
}
// 需要増强的类
function Robot(name) {
this.name = name;
}
// 増強
augment(Robot, Moveable, 'walk', 'run'); // Moveable から walk と run を継承
augment(Robot, Souled); // Souled の全属性を継承
// test
var robot = new Robot('little boy');
robot.walk(); // walked slowly
robot.run(); // ran quickly
robot.smile(12); // smiled as 12 year's old kid
部分的な継承と多重継承を簡単に実現でき、古典的な継承メカニズムの束縛を解除し、コードの再利用をより柔軟にします
いくつかの JS ライブラリは Mixin の実装を提供しています。例えば Underscore の _.extend メソッド、JQuery の extend メソッド、YUI の mix/augment/extend/merge メソッドなどです
三.Mixin パターンの欠点
Mixin は非常に柔軟なコードの再利用方法ですが、機能をプロトタイプオブジェクトに注入すると、プロトタイプの汚染と関数の出所に関する不確実性が生じ、大規模システムでは深刻な問題となる可能性があります。詳細なドキュメントを通じて関数の出所が不確実という問題を解決できますが、プロトタイプの汚染は避けられません
参考資料
-
『JavaScript デザインパターン』
コメントはまだありません