从超类静态方法内部调用子类静态方法

Call subclass static method from inside superclass static method

我有一大堆小的、相关的 class 通过接口 class 链接在一起。所有 classes 都实现了一个静态方法,该方法检索和处理特定于 class 的数据。

该静态方法的输出至少需要以两种方式进行格式化。由于从一种格式到另一种格式的转换总是相同的并且相当微不足道(虽然很长),我想我会在 superclass 中将它实现为一个具体的、密封的、静态的方法。

但是,后来我运行陷入了以下问题:

% (in Superclass.m)
classdef SuperClass < handle

    methods (Static, Abstract)
        [arg1, arg2] = subsStaticMethod;            
    end

    methods (Sealed, Static)

        function [other_arg1, other_arg2] = supersStaticMethod

            % Get data here
            [arg1, arg2] = (???).subsStaticMethod

            % transform data here
            % ...

        end

    end

end

% (in Subclass.m)
classdef SubClass < SuperClass 

    methods (Static)

        function [arg1, arg2] = subsStaticMethod
            % Get class-specific data here
            % ...
        end

    end

end

据我所知,使用此设计调用 SubClass.supersStaticMethod() 是不可能的,因为需要使用 class 名称显式调用静态方法。也就是说,没有办法在上面的SuperClass.supersStaticMethod中插入subclass名字来代替(???)

我尝试过的事情:

我知道我可以通过使 supersStaticMethod 非静态并在临时实例(如 SubClass().supersStaticMethod())上调用该方法来解决这个问题。或者在每个 subclass 中创建一个小包装方法,它只调用 superclass 方法,并以 mfilename('class') 作为参数。或者其他 100 种看起来同样笨拙的东西中的任何一种。

但我真的很想知道是否有一些 meta.class 技巧或什么可以干净地解决这个问题。我所发现的只是 this dated thread,它以编程方式处理 MATLAB 命令行以获取 subclass 名称。

但是,我的 classes 将在 scripts/functions 中使用,命令行使用将仅用于调试目的...

有什么想法吗?

以下是我的骇人听闻的建议。思路是将当前调用class存储在SuperClass的一个"static variable"中,然后查询该字段并在feval中使用它来调用正确的subclass' 方法。几点说明:

  • 它只能在你不进行一些并行计算的情况下工作(即在共享内存架构下一次从多个线程调用 SubClass#.supersStaticMethod - 在这种情况下调用 class 字段将被不规律地覆盖)。
  • SuperClass's supersStaticMethod cannot be Sealed, though the subclasses' 版本 可以.
  • "static variable" 在 SubClass.supersStaticMethod 之后被清除,以确保此方法只被子class.
  • 调用
  • 出于演示目的,我已将 matlab.mixin.Heterogeneous 添加为 SuperClass 的超级 class。

classdef SuperClass < handle & matlab.mixin.Heterogeneous

  properties (Abstract = true, Access = private, Constant = true)
    subclass@meta.class scalar;
  end

  methods (Static, Abstract)
    [arg1, arg2] = subsStaticMethod;
  end

  methods (Sealed, Static)
    function out = currentClass(input) % < the closest thing in MATLAB to a static variable
      persistent currentClass;
      if nargout == 0 && nargin == 1 % "setter" mode
        currentClass = input;
        out = [];
      else % "getter" mode
        out = currentClass;
      end      
    end
  end

  methods (Static)

    function [other_arg1, other_arg2] = supersStaticMethod

      % Who am I?
      whosCalling = SuperClass.currentClass();
      if isempty(whosCalling) || ~isa(whosCalling,'meta.class')
        [other_arg1,other_arg2] = deal(NaN);
        return
      else
        whosCalling = whosCalling.Name;
      end

      fprintf(1,'\nCalled from: %s\n', whosCalling);
      % Get data here
      [arg1, arg2] = feval([whosCalling '.subsStaticMethod']);

      % transform data here
      other_arg1 = arg1+arg2; other_arg2=[arg1(:);arg2(:)];
      fprintf(1,'other_arg1: %s, other_arg2: %s\n',...
                num2str(other_arg1), mat2str(other_arg2));

      % Clear the current class
      SuperClass.currentClass([]);
    end
  end

end

classdef SubClass1 < SuperClass

  properties (Constant)
    subclass@meta.class scalar = ?SubClass1;
  end

  methods (Static)    
    function [other_arg1, other_arg2] = supersStaticMethod
      SubClass1.currentClass(SubClass1.subclass);
      [other_arg1, other_arg2] = supersStaticMethod@SuperClass;
    end

    function [arg1, arg2] = subsStaticMethod
      arg1 = -1; arg2 = -2;
    end            

  end % static methods 
end % classdef

classdef SubClass2 < SuperClass

  properties (Constant)
    subclass@meta.class scalar = ?SubClass2;
  end

  methods (Static)    
    function [other_arg1, other_arg2] = supersStaticMethod
      SubClass1.currentClass(SubClass2.subclass);
      [other_arg1, other_arg2] = supersStaticMethod@SuperClass;
    end

    function [arg1, arg2] = subsStaticMethod
      arg1 = 1; arg2 = 2;
    end            

  end % static methods 
end % classdef

然后你可以这样测试:

function q31269260

arr = [SubClass1, SubClass2];
for ind1 = 1:numel(arr)
  arr(ind1).supersStaticMethod;
end
%  arr.supersStaticMethod would not work because elements are treated as "instances" of
%  SuperClass, whose supersStaticMethod should not be called directly.

输出为:

Called from: SubClass1
other_arg1: -3, other_arg2: [-1;-2]

Called from: SubClass2
other_arg1: 3, other_arg2: [1;2]