如何按需加载属性?

Posted

技术标签:

【中文标题】如何按需加载属性?【英文标题】:How to load a property on demand? 【发布时间】:2018-07-16 15:44:35 【问题描述】:

我想按需加载一个属性,但我无法让它工作。 我有一个具有瞬态属性foo 的类。因此,保存对象时不会存储属性。当我使用调用属性 'foo' 的方法时,我希望 foo 的值从单独的 mat 文件加载并存储到对象中,只要它在工作区中。

我尝试了一些 get 和 set 方法,但无法正常工作。这可能吗?还是我总是添加一行代码来加载属性?下面的代码没有做我想要的,但它给出了我尝试的指示。

此外,下面的代码在使用该属性时会不断加载 foo.mat 文件。我只想加载一次 foo.mat 并将其存储为属性并从那里检索数据而不是加载。我的问题的原因是 foo 属性相当大,即一个本身具有许多属性的类。我只想在需要时加载它,不想将它存储在 foobar 类本身中。

classdef foobar
    properties(Transient = true)
        foo
    end
    methods
        function value = get.foo(obj)
            if isempty(obj.foo)
                value = load('foo.mat');
                disp('load foo.mat');
            end
        end
        function obj = set.foo(obj,value)
            obj.foo = value;
        end
    end
end

【问题讨论】:

“无法正常工作”的意思是……究竟是什么?您的示例运行良好。 好点来更好地解释它。使用我发布的脚本,例如,每次执行 object.foo 时,它都会加载 foo.mat 文件,而不是只加载一次。 Default Property 可能是更好的选择。 我不想要默认属性,因为它非常大。我只想在调用的时候加载,加载一次。 【参考方案1】:

这里有两个主要问题:

    在您的get.foo 方法中,一旦您加载了值,就永远不会更新对象中foo 的值,因此它保持为空。

    即使您尝试在get.foo 方法中更新foo,它在原始 对象中仍然是空的,因为您的foobar 类是value class。修改值类对象的方法必须将修改后的对象作为输出返回,因为它们本质上是在修改对象的副本。值类的set 方法返回用于覆盖原始对象的修改对象,但get 方法不返回修改对象(因为通常不希望它们修改它们)。要绕过这个限制,您需要 handle class 的类似引用行为(这里是 a related question,您可能需要查看更多背景信息)。

因此,为了获得您想要的行为,您必须将 foobar 实现为句柄类的子类,并在首次加载时更新 foo 字段:

classdef foobar < handle    % Inherit from handle class

  properties(Transient = true)
    foo
  end

  methods

    function value = get.foo(obj)
      if isempty(obj.foo)
        value = load('foo.mat');
        disp('load foo.mat');
        obj.foo = value;       % Update foo
      end
      value = obj.foo;         % Return current foo value
    end

    function set.foo(obj, value)  % Return value is unnecessary for handle class
      obj.foo = value;
    end

  end

end

这应该会为您提供您想要的行为(即 foo 仅在首次访问时加载)。

注意: 任何调用get.foo 的方法都将初始化foo。您可能会忽略的一种方法是disp 方法,因为它是默认为类创建的。 default display for a class object 将显示类名,后跟非隐藏公共属性列表及其值。请注意,当我从上面创建带有和不带分号的 foobar 类对象时会发生什么:

>> f = foobar;  % Display is suppressed
>> f = foobar

f = 

load foo.mat               % foo gets initialized...
  foobar with properties:

    foo: [1×1 struct]      % ...because its value is displayed here

如果您想避免这种情况,您可以将overload the disp function 用于您的foobar 对象,这样显示对象就不会访问(并因此初始化)foo。比如可以在上面的foobar类中加入这个方法:

    function disp(obj)
      disp('     foobar object');
    end

现在你不会在显示对象时初始化foo

>> f = foobar

f = 

     foobar object  % foo not yet initialized
>> a = f.foo;
load foo.mat        % foo initialized because we accessed it

【讨论】:

你的答案几乎是我想要的,但最后一个注释对我来说是个问题。我调用属性foo 的大多数方法都存在于对象中。我只想加载 foo 如果有方法调用它,以便在 foobar 的实例已经存在时不加载属性 foo @SGeurts:我在笔记中添加了更多细节。您所要做的就是重载disp 方法,使其无法访问foo 太棒了! set 方法甚至不是我的目的所必需的。我还发现在变量菜单中显示对象会启动加载foo。我仍然不明白的是为什么需要 Handle 类而不是 Value 类。 @SGeurts:我添加了一些关于值和句柄类的更多细节。希望这能让它更清楚。 我可以将property属性设置为'true',这样就解决了。

以上是关于如何按需加载属性?的主要内容,如果未能解决你的问题,请参考以下文章

利用 React/Redux/React-Router 4/webpack 开发大型 web 项目时如何按需加载

AngularJS项目中如何实现按需加载js文件?

CSS 实现加载圆环

如何在 Nativescript 中重新启动按需加载?

分页库:如何按需重新加载部分数据?

Echarts的按需加载