【问题标题】:Destructing Matlab Singleton class instance without calling `clear all`在不调用“全部清除”的情况下破坏 Matlab Singleton 类实例
【发布时间】:2015-07-18 13:03:30
【问题描述】:

根据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

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

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

有没有人知道一种无需调用clear all 就可以在 Matlab 类的静态方法中清除持久变量的方法?或者,换一种方式,有没有人知道如何在不使用persitent 变量的情况下实现单例设计模式?或者,至少,如何在单元测试中调用clear all 而不会破坏单元测试基础架构?

【问题讨论】:

    标签: matlab unit-testing oop singleton persistent


    【解决方案1】:

    您必须使用delete 或查看此doc

    clear 系列中,您也可以查看clear classes,但这不符合您的需要,因为它与clear all 做同样的事情,而且它删除了类定义。

    您无需更改单例类型类的设计,要销毁实例化的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 的句柄,但它知道该对象已被删除。

    因此,在您的课程设计中,您可以在继续其他操作之前检查localObj 的状态。

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

    【讨论】:

      【解决方案2】:

      我的第一个想法是尽可能避免单例和其他形式的全局状态,这不仅是为了可测试性,也是为了代码的简洁性和接口完整性。更多信息herehere

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

      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 类也会清除分析器数据,因此您将无法使用 CodeCoveragePlugin 有效地测量代码覆盖率。

      只要您对用户清除唯一实例的能力感到满意,Hoki 的回答就很好,这也可以清除您的应用程序所依赖的全局状态,如果您不这样做,则可能会导致错误小心。

      希望有帮助!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-07
        • 2023-01-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多