在不调用`clear all`的情况下破坏Matlab Singleton class实例

Destructing Matlab Singleton class instance without calling `clear all`

根据 Matlab documentation,为了创建单例设计模式,您需要在静态函数中为单例对象实例设置一个 persistent 变量,即:

classdef (Sealed) SingleInstance < handle
  methods (Access = private)
    function obj = SingleInstance
    end
  end
  methods (Static)
    function singleObj = getInstance
      persistent localObj
      if isempty(localObj) || ~isvalid(localObj)
        localObj = SingleInstance;
      end
      singleObj = localObj;
    end
  end
end

几乎不可能 'destruct' 单例实例。我试过 clear SingleInstanceclear getInstance()clear SingleInstance.getInstance()clear functionsclear variables 和其他组合。在 SingleInstance class 的 getInstance() 静态方法中 localObj 持久变量的唯一方法是调用 clear all.

我可以在调用我的 Matlab OO 应用程序之前调用 clear all。但是,我正在使用 Matlab 单元测试基础结构,并且有一些单元测试,我想在其中测试实例化单例 classes 的不同方法。但是,为此我需要调用 clear all,这会使 Matlab 单元测试基础结构停止工作。

有谁知道一种无需调用 clear all 即可清除 Matlab classes 静态方法内部持久变量的方法吗?或者,换句话说,有人知道如何在不使用 persitent 变量的情况下实现单例设计模式吗?或者,至少,如何在不破坏单元测试基础结构的情况下在单元测试中调用 clear all

你必须使用delete or look at this doc

clear 系列中,您还可以查看 clear classes,但这不符合您的需要,因为它的功能与 clear all 相同,而且它删除了 classes定义。

您无需更改单例类型的设计 class,要销毁实例化的 handle 对象,您必须使用 delete object2dispose。当您使用 clear object2dispose 时,您只清除工作区中保存对象句柄的变量,但不会破坏对象本身。这就是为什么当你调用 getInstance 方法时你仍然看到句柄保存在 localObj 持久变量中(这是它的目的之一,保存你可能丢失的句柄)。

所以如果我使用

sobj = SingleInstance.getInstance %// instantiate object
clear sobj                          %// clear it ? (... not really)

sobj = SingleInstance.getInstance %// To see the state of "localObj"

我在执行第三行的过程中在调试器中停止了,我得到:

当我调用 clear 时,我的变量 sobj 从工作区中消失了,但是对象仍然存在于内存中(并且句柄仍然由 localObj 变量保留)。

如果我现在将第二行替换为

delete(sobj)

在您的工作区中,您将获得:

>> sobj
sobj = 
  handle to deleted SingleInstance

在调试器中对 getInstance 的下一次调用时,我得到:

出现在工作区中的 localObj 仍然显示为 SingleInstance 的句柄,但它知道该对象已被删除。

所以在您的 class 设计中,您可以在继续其他操作之前检查 localObj 的状态。

函数 isvalid 可用于了解句柄是否指向真实对象。

我的第一个想法是,只要有可能,您就应该避免单例和其他形式的全局状态,这不仅是为了可测试性,也是为了代码的整洁和接口的完整性。更多信息 here and here.

另一种想法是您可以发出以下调用:

classdef FuadTest < matlab.unittest.TestCase

    methods(Test)
        function testSomething(testCase)
             clearClasses;
             % Do other stuff
        end
    end
end

function clearClasses
clear classes;
end

这里的重点是将 clear 类 调用放入它自己的本地函数(或私有方法、静态方法等),这样你就可以在它自己的范围内调用 clear 而不是清除所有测试方法中的其他变量(例如,testCase)。如果它在它自己的函数中,则不需要该范围内的任何其他变量,因此您可以有效地清除 类。

然而,请注意,以这种方式使用 clear 类 确实是一种试图告诉你一些事情的气味(主要是为了避免全局状态),你应该期望 运行 进入特质。例如,我相信调用 clear 类 也会清除探查器数据,因此您将无法使用 CodeCoveragePlugin.

有效地测量代码覆盖率

Hoki 的回答很好,只要您同意用户清除唯一实例的能力,这也可以清除您的应用程序所依赖的全局状态,并且有可能在未来导致错误,如果您不小心

希望对您有所帮助!