Is it memory inefficient to instantiate classes in a getter method? What OOP design prevents this?

huangapple go评论75阅读模式
英文:

Is it memory inefficient to instantiate classes in a getter method? What OOP design prevents this?

问题

我有一个获取方法,用于从反序列化数据中实例化类。我怀疑这是一种非常低效的做法。

class Container {
  get content() {
    let contentList = []
    for (let c of this._content) { // this._content 是一个对象数组
      contentList.push(new ContentTypes[c.type](c)) //ContentTypes 是类型名称和类之间的映射
    }
    return contentList
  }
}

在面向对象编程领域中,适当的设计模式是什么?

英文:

I have a getter method that instantiates classes from deserialized data. I suspect this is a terribly inefficient way of doing things

class Container {
  get content() {
    let contentList = []
    for (let c of this._content) { // this._content is an array of objects
      contentList.push(new ContentTypes[c.type](c)) //ContentTypes is a mapping between type names and classes
    }
    return contentList
  }
}

What's the appropriate design pattern in OOP land?

答案1

得分: 1

无论代码是在getter还是方法中,效率都不会改变。但改变的是使用你的类编写代码的人的期望

我不希望在对象上访问属性会产生太多开销。所以当我使用Container的实例时,如果我看到一个contents属性,我不会期望它会做很多工作。但你的代码确实做了一些(有点)。

我可以选择:

  1. 保留返回内容的副本(使其不可变),仅在其依赖项更改时丢弃它,或者

  2. 将其设置为方法(明确指定)。

(或者两者都可以做。)

我期望方法调用会比属性访问产生更多开销。我不知道是否有特定的面向对象编程原则可以引用这一点,但这是我的经验观点(可能有或没有价值)。

但要注意,在实际应用中有反例。一个著名且直接适用的例子是DOM元素的innerHTML属性,它是一个访问器属性,当你使用它时会执行相当多的工作。

以下是一个示例,返回一个不可变的对象,您保留并重新返回它,但在其基础数据更改时失效:

class Container {
    constructor() {
        this._content = [];
        this._exposedContent = null;
    }

    addContent(content) {
        this._content.push(content);
        this._exposedContent = null; // 如果有缓存副本,则将其标记为无效
    }

    get content() {
        // 我们是否有缓存副本?
        if (!this._exposedContent) {
            // 没有,创建它
            this._exposedContent = this._content.map(
                c => Object.freeze(new ContentTypes[c.type](c))
            );
        }
        return this._exposedContent;
    }
}

(您还可以在一段时间后使副本失效。)

但是否值得使用内存开销和复杂性来权衡它是否比实际在您的content访问器中的代码更有价值,这是一个判断性问题。我的默认立场是使用一个方法而不缓存(例如getContent或类似的方法),但这是一个判断性问题。

英文:

Whether the code is in a getter or a method, the efficiency doesn't change. But what changes is the expectation of the person writing code using your class.

I don't expect accessing a property on an object to incur much overhead. So when using an instance of Container, if I see a contents property, I'm not going to expect it to do a lot of work. Yours does (a bit).

I would either:

  1. Keep a copy of what you return (making what you return immutable) and only discard it when the things it relies on change, or

  2. Make it a method (explicitly).

(Or I might do both.)

I expect method calls to incur more overhead than property accesses. I don't know if there's a specific OOP principle one can cite about that, but that's my view from experience (for what it may or may not be worth).

But, note that there are counterexamples out in the wild. A famous and directly applicable one is the innerHTML property of DOM elements, which is an accessor property that does a fair bit of work when you use it.

Here's an example of returning an immutable thing you keep and re-return, but invalidate when its underlying data changes:

class Container {
    constructor() {
        this._content = [];
        this._exposedContent = null;
    }

    addContent(content) {
        this._content.push(content);
        this._exposedContent = null; // Invalidating the cached copy if any
    }

    get content() {
        // Do we have a cached copy?
        if (!this._exposedContent) {
            // No, create it
            this._exposedContent = this._content.map(
                c => Object.freeze(new ContentTypes[c.type](c))
            );
        }
        return this._exposedContent;
    }
}

(You might also expire the copy after a period of time.)

But it's a judgement call whether it's worth the memory overhead and complexity vs. what your code actually in your content accessor. My default position would be to use a method instead (getContent or similar) and not cache, but it's a judgement call.

huangapple
  • 本文由 发表于 2020年1月6日 19:30:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/59611344.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定