web-dev-qa-db-ja.com

グローバル変数を介して親の関数を呼び出す子オブジェクト

私はSessionオブジェクトを持っています。そのうちの1つのグローバルインスタンスsessionが現在のセッションを保持しています。現在のセッションは、サーバーに永続化し、やり直しのやり直しなどを処理できます。

セッションは、Objectsのインスタンスを保持します。この例では、基本的にCarsオブジェクトのセットです。ユーザーが変更したとき車の位置を表す地図上のマーカー。対応するCarオブジェクトを更新し、セッションを保存してやり直してサーバーに永続化できるようにします。

不完全な図:

enter image description here

コード:

function Session(sessionId, objectsSave){
    this.objects = new Objects();

    if (objectsSave !== undefined)
        this.objects.restore(objectsSave);

Session.prototype.saveSession = function() {
    var save = this.objects.save();
    // persist to server and add to redoStack
}

function Objects() {
    this.objects = [];
}

Objects.prototype.restore = function(save){
    var objects = [];

    save.forEach(function(obj) {
        objects.Push(Car.prototype.restore(obj));
    }); 

    this.objects = objects;
};

function Car(){
    this.markerOnMap = new Marker();
    this.markerOnMap.onDrag = this.setLocation;
    this.markerOnMap.onDragEnd = session.saveSession;  // here using the global variable, does not work when instantiating Session with a save object

Car.prototype.setLocation = function(e) {
    this.location = e.location;
}

var session = new Session();

Sessionをインスタンス化するときに、(「悪いデザイン」の感覚以外に)問題が発生します。サーバーからのデータ。 Sessionコンストラクターで新しいObjectsインスタンスを作成し、それをsaveで復元すると、Carオブジェクトが作成され、グローバル変数sessionの関数を参照しようとします。ただし、このコードはsessionのコンストラクターから呼び出されたため、Sessionはまだ割り当てられていません。たとえば、それを次のように変更しました:

        this.markerOnMap.onDragEnd = function(){session.saveSession()};

または、thisコンストラクタからSessionのコンストラクタまで、Carを渡します。私はグローバル変数、すべての循環参照を持つために何が悪いのかわかりません、またはより良い解決策がありますか?

2
Adam

実際、構築プロセスには設計上の欠陥があります。Carは作成時にSessionを必要とします。この依存関係は、Carを使用してSessionをデシリアライズすると問題になります。

問題は 単一の責任の原則: を尊重しないためです。Carを作成するときは、オブジェクトを作成するだけで、コンテナーに挿入しないでください。この2番目の手順は、特定の目的でCarをインスタンス化する関数/オブジェクトの責任です。

あなたの場合、 ビルダーのデザインパターン を検討することをお勧めします。この設計では、複雑なオブジェクト(ここではセッション)の構築を、その部品の構築と組み立てに分けています。これには、パーツを独立して構築できることが必要です。

1
Christophe

あなたの「悪いデザイン」の感覚は正当化されます。グローバル変数を介してオブジェクト間で通信することは、間違いなくコードのにおいです。

SessionコンストラクターでCarインスタンスへの参照を提供することは、私にとってそれほど悪いことには聞こえません。または、Carは、saveSession()を直接呼び出すのではなく、saveイベントを発生させることができます。次に、イベントリスナーをSessionにアタッチするためにファクトリ関数が必要になりますが、CarSessionに直接依存しません。

0
JacquesB