2

Room という名前のクラスがあり、そのプロパティの 1 つとしてすべての Player エンティティを含む配列があります。

players = [];

Room クラスには、実際にラウンドに参加したプレイヤーのみを返すメソッドがあります。

// below method is called by the room's timer

var getPlayersWhoFinished = function() {
    playersWhoFinished = [];
    for (i = 0; i < players.length; i++) {
        if (players[i].isFinished()) {
            playersWhoFinished.push(players[i]);
        };
    };
    return playersWhoFinished;
}

したがって、上記を Room クラスにそのまま残すことができることはわかっていますが、すでに大きなクラス (300 行以上) に、より複雑なマッピングを持つ他の 3 つの関数が既にあります。これらの種類のメソッドを他のクラスにカプセル化する方法がわかりません。それらは Room クラスと適切なユーザーに送信されるすべての Room 参照に非常に密接に関連しているためです。

上記のコードを変更して Player クラスに挿入することは、ある程度理にかなっていますが、これを機能させる唯一の方法は、静的メソッドを使用してルーム オブジェクトをそれに送信することです。

// players is now a member of the Player class

Player.getPlayersWhoFinished = function(room, players) {
    playersWhoFinished = [];
    for (i = 0; i < players; i++) {
        if (players[i].getRoom() == room) {
            playersWhoFinished.push(players[i]);
        }
    }
    return playersWhoFinished;
}

とにかく、これは面倒で非効率に思えます。Room クラスをできるだけ柔軟にする方法を見つけるのに本当に苦労しています。

4

2 に答える 2

1

このgetPlayersWhoFinished()メソッドは、プレイヤーを追跡するオブジェクトである Room に属しています。また、完成したプレーヤーを見つける必要があるたびに、O(n) の複雑さで検索を実行していますが、これは改善することができます。

プレイヤーが終了するたびに呼び出されるコールバック手段を持つことができます:

Player.prototype.onFinished = function() {
    this.getRoom().addFinished(this);
}

そして、すべての完成したプレーヤーを含む Room でプライベート配列を管理します。

function Room() {
    this._finishedPlayers = [];
}

Room.prototype.addFinished = function(player) {
    this._finishedPlayers.push(player);
}

Room.prototype.getPlayersWhoFinished = function() {
    return this._finishedPlayers;
}

補足として、変数は常に var で宣言する必要があります。そうしないと、グローバル スコープ (つまり、通常はウィンドウ オブジェクト) で宣言されます。

于 2013-07-29T19:43:29.260 に答える
1

ロジックをオブジェクトとコレクションに分割することを検討してください。バックボーンが提供するもの (モデル、コレクション) に似ています。

通常、コレクション ロジックは含まれるオブジェクトに固有ですが、いくつかの共有機能 (単純な反復、フィルターなど) も備えているため、ジェネリック コレクションを作成し、継承を通じてその特定のニーズに合わせてメソッドを追加できます。格納するオブジェクト。

したがって、あなたの部屋は次のようになります。

function Room() {
  // ..
  this.players = new PlayerCollection();
  // ..
}

コレクションのために、いくつかの「ボーナス」メソッドを追加したので、次のようになります。

function Collection() {
  this.list = [ ];
  this.length = 0;
}

// adds item
Collection.prototype.add = function(item) {
  this.list.push(item);
  this.length = this.list.length;
}

// removes by index
Collection.prototype.remove = function(index) {
  this.list.splice(index, 1);
  this.length = this.list.length;
}

// finds one item based on filter function, and triggers callback with item and index
Collection.prototype.findOne = function(fn, callback) {
  for(var i = 0, len = this.list.length; i < len; ++i) {
    var result = fn(this.list[i]);
    if (result) {
      return callback(this.list[i], i);
    }
  }
  return callback(null, -1);
}

// filters off 
Collection.prototype.filter = function(fn) {
  return this.list.filter(fn);
}

次に、終了したプレーヤーを除外するための追加のメソッドを持つ PlayerCollection を定義します。

function PlayerCollection() {
  Collection.call(this);
}
// some inheritance here
PlayerCollection.prototype = Object.create(Collection.prototype);
PlayerCollection.prototype.constructor = PlayerCollection;

// returns list of finished players
PlayerCollection.prototype.finished = function() {
  return Collection.prototype.filter.call(this, function(player) {
    return player.isFinished();
  });
}

filter特注のクエリを作成するのに役立つため、そのメソッドを再利用できます。

ルーム ロジックは次のようになります。

var room = new Room();
// add some players to room
// ...
var finishedPlayers = room.players.finished(); // what you need

明確で単純に見えるだけでなく、すべてのコレクション ロジックが Room から離れているため、ゲーム コード全体で簡単に再利用できます。そして、一箇所を改善すると、全体が改善されます。

ロジックをこのように抽象化することで、コードをスケーリングし、依存関係を分離するのに役立ちます。
ブラウザのサポートに注意してください。-IE8 が必要な場合は、ここfilterから shim を入手してください。

于 2013-07-29T16:44:41.623 に答える