サブクラス化を試みる代わりに、ダックタイピング イニシアチブを使用してコンポーネントと依存性注入を拡張してみませんか?
var Duck = function (flyable, movable, speakable) {
this.speak = speakable.speak;
this.fly = flyable.fly;
this.position = movable.position;
flyable.subscribe("takeoff", movable.leaveGround);
flyable.subscribe("land", movable.hitGround);
}
var duck = new Duck(new BirdFlier(), new BirdWalker(), new Quacker());
var plane = new Duck(new VehicleFlier(), new Drivable(), new Radio());
duck.speak(); // "quack"
plane.speak(); // "Roger"
plane
が と同じコンストラクタを喜んで使用していることに注意してくださいduck
。
そもそもコンストラクタさえ必要としません。
工場も同様に機能します。
DuckTyping のポイントは、オブジェクトの構築は、オブジェクトを使用するプログラムの関心事ではないということです。
メソッド/プロパティ名が同じである限り、サブ/スーパー/静的継承に関係なく、プログラムはそれらを使用します。
編集: サンプルコンポーネントを追加
ここには、私が結び付けているいくつかの異なるアイデアがあります。したがって、一度に1ドット:
まず、ダックタイピングの基本的な前提:
// the basic nature of duck-typing
var sheriff = {
gun : {
aim : function () { /* point gun somewhere */ },
bullets : 6,
fire : function () {
if (this.bullets === 0) { return; }
this.bullets -= 1;
/* ... et cetera */
}
},
draw : function () {
this.gun.aim();
this.gun.fire();
}
},
cartoonist = {
pen : { scribble : function () { /* ... */ } },
draw : function () { this.pen.scribble(); }
},
graphicsCard = {
pixels : [ /* ... */ ],
screen : { /* ... */ },
draw : function () {
pixels.forEach(function (pixel) { screen.draw(pixel); });
}
};
// duck-typing at its finest:
sheriff.draw();
cartoonist.draw();
graphicsCard.draw();
目標は、それがどのような種類のオブジェクトであるかをわざわざチェックしない関数を書くことです:
function duckDraw (array) { array.forEach(function (obj) { obj.draw(); }); }
duckDraw([ sheriff, cartoonist, graphicsCard ]);
したがって、ウミガメ、イルカ、クジラ、潜水艦、ミノーがいる場合、プログラムはそれらの泳ぎ方の違いを気にする必要はありません。それらがすべてできることを気にするだけ.swim();
です。各アイテムは、それ自体と、必要なことを行う特別な方法について心配することができます。
ダックタイピング
次は依存性注入です。ある意味では、依存性注入もダックタイピングを使用しますが、クラスの外側ではなく内側で (または、私が上で行ったようにそれを行う場合は、内側から開始し、ダックタイピングを許可します)外側も同様)。
次のように考えてみてください。人が何かを継承する代わりに、ただそれを手渡すだけです。
soldier
、 a sniper
、plane
および がある場合tank
、それぞれに が必要gun
です。サブクラス化して全員が発砲できるようにする代わりに... ...さまざまな種類の銃を作成して、ニーズに合わせて必要なものをすべて渡してはどうでしょうか?
var Rifle = function () {
this.reload = function () {};
this.fire = function () { /* ... */ };
},
SniperRifle = function () {
this.reload = function () {};
this.fire = function () {};
},
MachineGun = function () {
this.reload = function () {};
this.fire = function () {};
},
Cannon = function () {
this.reload = function () {};
this.fire = function () {};
};
これで、さまざまな種類の銃ができました...関数名が同じで、すべて弾丸を扱うため、サブクラス化を試みることができると思うかもしれません... ...しかし、あなたはそうしませんする必要はありません-これらの銃はどれも、発砲またはリロードするときに同じことをしません... ...そのため、他の言語でメソッド/プロパティに書き込むoverrides
ことになり、役に立たなくなります。abstract virtual
それらを取得したので、それらを「注入」する方法と、それが何をするかを確認できます。
var Soldier = function (gun) {
this.currentGun = gun;
this.inventory = {
guns : [ gun ]
};
this.attack = function () { this.currentGun.fire(); };
};
var Sniper = function (gun) {
this.currentGun = gun;
this.inventory = {
guns : [ gun ]
};
this.attack = function () { this.currentGun.fire(); };
};
var Plane = function (gun) {
this.currentGun = gun;
this.inventory = {
guns : [ gun ]
};
this.attack = function () { this.currentGun.fire(); };
};
var Tank = function (gun) {
this.currentGun = gun;
this.inventory = {
guns : [ gun ]
};
this.attack = function () { this.currentGun.fire(); };
};
var soldier = new Soldier( new Rifle() ),
sniper = new Sniper( new SniperRifle() ),
plane = new Plane( new MachineGun() ),
tank = new Tank( new Cannon() );
これで、彼らが銃を呼ぶクラスができました。彼らは銃の種類を気にせず、ただ機能します。なぜなら、銃は銃の仕組みを知っており、戦闘員は銃の発砲方法を知っているからです。プログラムは、戦闘員に発砲するように伝える方法を知っています。
しかし、もう少し詳しく見てみると、各戦闘員の内部コードは今のところ 100% 同じです。
では、特殊なコンポーネントを与えることができる「戦闘員」を持たないのはなぜですか?
var Combatant = function (gun) {
this.currentGun = gun;
this.inventory = {
guns : [ gun ]
};
this.attack = function () { this.currentGun.fire(); };
};
var soldier = new Combatant( new Rifle() );
したがって、コンストラクターの内部はダックタイピングgun
であり、戦闘員に異なるクラスがあり、各クラスにfire
メソッドがある場合、ゲームロジックでユニットをダックタイピングすることもできます.
最終的に、コンストラクターはモジュールを保持するだけです。1 つのモジュールは射撃を処理し、1 つのモジュールは地面の動きを処理し、1 つを描画用に、もう 1 つをプレイヤー コントロールに、などなど...コンストラクターは、ピースを接触させる以外に何もする必要はありません。さまざまな種類の銃、さまざまな種類の動き、さまざまな種類のヘルスを与えることで、ユニットを特別なものにすることができます。これらは内部で異なる動作をしますが、パブリック アクセスのプロパティとメソッド名は同じです。