如何使用循环引用处理类对象?

时间:2016-04-28 11:34:50

标签: javascript oop ecmascript-6

我正在考虑简单的问题。我给了一个例如Model

的课程
class Model {
    constructor(parameters = {}) {
        this.id = parameters.id;
    }
}

您可以看到我们可以创建新的Model对象,例如:let model = new Model()。更复杂的例子如下所示:

//we have some data given from API maybe?
let parameters = {id: 1};
let model = new Model(parameters );

在这里,我开始徘徊如果给定id的对象已经存在怎么办?

问题是我应该使用什么模式来实例化给定id一次的对象?

让我们进一步说明:如果我们将使用循环引用获取嵌套对象,该怎么办?假设我们有另一个名为AnotherModel的类,我们的代码如下:

class Model {
    constructor(parameters = {}) {
        this.id = parameters.id;
        this.anotherModel= nulld;

        if (parameters.anotherModel) {
            this.anotherModel= parameters.anotherModel instanceof AnotherModel
                ? parameters.anotherModel
                : new AnotherModel(parameters.anotherModel);
        }
    }
}

class AnotherModel {
    constructor(parameters = {}) {
        this.id = parameters.id;
        this.models = [];

        if (parameters.models) {
            for (let i = 0; i < parameters.models.length; i++) {
                let model = parameters.models[i];
                model.anotherModel= this;
                this.models.push(new Model(model));
            }
        }
    }
}

因此AnotherModel包含Model s和Model对象的集合,其中包含对AnotherModel的引用。

解决此问题的好方法是什么?我们想要实现的是只有一个具有相同id的对象。

我在想的是做一些ObjectPool,我将存储给定类或类的所有对象,当实例化新对象时,如果不存在或者返回现有对象,我们的池会创建一个新对象吗? / p>

但是这里有一些不足之处,例如我们已经编写了一些我们必须重构的代码并改变了它们从new Model()ObjectPool.get(Model, parameters)的实例化方式?

你有什么想法?

1 个答案:

答案 0 :(得分:3)

您可以使用对象池(在类或其外部)来跟踪您的实例。通过在构造函数中定义它,您仍然可以使用:

实例化模型
new Model();
new AnotherModel();

如果池中已存在id,则只需返回现有实例。

课外:

const modelPool = {};

class Model {
    constructor(parameters = {}) {
        if (modelPool[parameters.id] instanceof Model) {
            return modelPool[parameters.id];
        }

        modelPool[parameters.id] = this;

        this.id = parameters.id;
        this.anotherModel= null;

        // ...
    }
}

const anotherModelPool = {};

class AnotherModel {
    constructor(parameters = {}) {
        if (anotherModelPool[parameters.id] instanceof AnotherModel) {
            return anotherModelPool[parameters.id];
        }

        anotherModelPool[parameters.id] = this;

        this.id = parameters.id;
        this.models = [];

        //...
    }
}

或者作为类(不是实例)上的(不可枚举,不可写,不可配置)属性:

class Model {
    constructor(parameters = {}) {
        if (Model.pool[parameters.id] instanceof Model) {
            return Model.pool[parameters.id];
        }

        Model.pool[parameters.id] = this;

        this.id = parameters.id;
        this.anotherModel= null;

        //...
    }
}

Object.defineProperty(Model, 'pool', {
    value: {}
});

class AnotherModel {
    constructor(parameters = {}) {
        if (AnotherModel.pool[parameters.id] instanceof AnotherModel) {
            return AnotherModel.pool[parameters.id];
        }

        AnotherModel.pool[parameters.id]

        this.id = parameters.id;
        this.models = [];

        //...
    }
}

Object.defineProperty(AnotherModel, 'pool', {
    value: {}
});

由@Vardius添加,还可以创建一个伪抽象类(因为JS没有抽象类),可以从中扩展。使用new.target.name,可以创建抽象类池中的命名空间:

class Entity {
    constructor(parameters = {}) {
        if (Entity.pool[this.constructor.name] && Entity.pool[this.constructor.name][parameters.id] instanceof Entity) {
            return Entity.pool[new.target.name][parameters.id];
        }
        Entity.pool[new.target.name][parameters.id] = this;
    }
}
Object.defineProperty(Entity, 'pool', {value: {} });