Matlab多态性

Mar*_*arc 9 oop polymorphism matlab matlab-class

我有两个新式的MATLAB类 - B&C,它们都是抽象父类的具体子类A. Ahgsetset(句柄类)的子类.我想将它们放在MATLAB中的数组中,并将它们视为As.它们大致定义为:

classdef A <hgsetget
methods
    function foo(this)
        %does some common stuff, then
        this.fooWorker;
    end
end %public Methods
methods(Abstract, Access=protected)
    fooWorker(this);
end %abstract Methods;
end

classdef B < A
methods(Access=protected)
    function fooWorker(this)
        %implementation
    end
end %protected Methods;
end
Run Code Online (Sandbox Code Playgroud)

但是,如果我这样做:

arr = [b c]; % where b & c are objects of type B & C respectively.
arr(1).foo;
arr(2).foo;
Run Code Online (Sandbox Code Playgroud)

MATLAB将告诉我两者都是类型B,如果我从A两个实现(foo)调用抽象方法,它实际上执行两个副本b.

但是,如果我颠倒顺序:

arr = [c b];
Run Code Online (Sandbox Code Playgroud)

它告诉我两者都是类型C,如果我尝试在两者上执行foo,它执行,基本上是两个副本c.

任何想法如何以多态方式使用子类?

我知道我可以把它们放在一个单元阵列中,并获得我需要的90%.但这有点像kludge.

Tho*_*son 17

您现在可以通过继承matlab.mixin.Heterogeneous在R2011a中完成此操作.例如,在您的代码中,抽象类将是:

classdef A < matlab.mixin.Heterogeneous
methods
    function foo(this)
        disp('In abstract parent');
        this.fooWorker;
    end
end
methods(Abstract, Access=protected)
    fooWorker(this);
end
end
Run Code Online (Sandbox Code Playgroud)

子类看起来像:

classdef B < A
methods(Access=protected)
    function fooWorker(this)
        disp('In B');
    end
end
end
Run Code Online (Sandbox Code Playgroud)

类似于'C'类.然后,这给出了MATLAB的以下输出:

>> b = B;
>> c = C;
>> arr = [b, c];
>> arr(1).foo
In abstract parent
In B
>> arr(2).foo
In abstract parent
In C
>> 
Run Code Online (Sandbox Code Playgroud)


gno*_*ice 5

不幸的是,MATLAB中数组的所有元素必须属于同一类型.当您连接不同的类时,MATLAB将尝试将它们全部转换为同一个类.

如果您已将某个类定义为低于或高于另一个类(使用InferiorClasses属性或INFERIORTO/SUPERIORTO函数),则会调用更高级类的方法.如果尚未指定类之间的关系,则两个对象具有相同的优先级,MATLAB调用最左侧的对象方法.这可能是为什么要arr = [b c];创建一个B类数组并arr = [c b];创建一个C类数组的原因.

选项1:单元阵列

如果要foo在对象上执行为类B定义的方法b,并且还要在对象上执行foo为类C定义的方法c,则可能必须使用单元数组和函数CELLFUN.如果foo没有返回值,您可以执行以下操作:

arr = {b,c};
cellfun(@foo,arr);  % Invoke foo on each element of the cell array
Run Code Online (Sandbox Code Playgroud)

选项2:有陪审团操纵多态行为的乐趣

为了好玩,我想出了一个技术上有效的潜在解决方案,但有一些局限性.为了说明这个想法,我整理了一些类似于你在问题中列出的样本类.这是抽象的超类classA:

classdef classA < hgsetget
  properties
    stuff
  end
  properties (Access = protected)
    originalClass
  end
  methods
    function foo(this)
      disp('I am type A!');
      if ~strcmp(class(this),this.originalClass)
        this = feval(this.originalClass,this);
      end
      this.fooWorker;
    end
  end
  methods (Abstract, Access = protected)
    fooWorker(this);
  end
end
Run Code Online (Sandbox Code Playgroud)

这里是子类的一个例子classB(classC在任何地方B被替换为完全相同,C反之亦然):

classdef classB < classA
  methods
    function this = classB(obj)
      switch class(obj)
        case 'classB'  % An object of classB was passed in
          this = obj;
        case 'classC'  % Convert input from classC to classB
          this.stuff = obj.stuff;
          this.originalClass = obj.originalClass;
        otherwise      % Create a new object
          this.stuff = obj;
          this.originalClass = 'classB';
      end
    end
  end
  methods (Access = protected)
    function fooWorker(this)
      disp('...and type B!');
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

构造函数用于classBclassC设计为使得两个类可以相互转换.该属性originalClass在创建时初始化,并指示该对象的原始类是什么.如果将对象从一个类转换为另一个类,则此属性将保持不变.

在该foo方法中,传入的对象的当前类将根据其原始类进行检查.如果它们不同,则在调用fooWorker方法之前首先将对象转换回其原始类.这是一个测试:

>> b = classB('hello');  % Create an instance of classB
>> c = classC([1 2 3]);  % Create an instance of classC
>> b.foo  % Invoke foo on b
I am type A!
...and type B!
>> c.foo  % Invoke foo on c
I am type A!
...and type C!
>> arr = [b c]  % Concatenate b and c, converting both to classB

arr = 

  1x2 classB handle

  Properties:
    stuff

  Methods, Events, Superclasses

>> arr(1).foo  % Invoke foo on element 1 (formerly b)
I am type A!
...and type B!
>> arr(2).foo  % Invoke foo on element 2 (formerly c)
I am type A!
...and type C!
Run Code Online (Sandbox Code Playgroud)

一个关键性的限制(除了作为一个小难看)是其中的情况下classB,并classC各自具有另一个没有的特性.在这种情况下,转换到另一个类然后转换回来可能会导致这些属性丢失(即重置为其默认值).但是,如果一个类是另一个类的子类,那么它具有所有相同的属性和thensome,那么就有一个解决方案.您可以将子类设置为优于超类(参见上面的讨论),这样两个类的连接对象将始终导致超类对象转换为子类.当在"多态"方法(foo如上所述)内转换回来时,不会丢失任何对象数据.

我不知道解决方案是多么可行,但也许它至少会给你一些有趣的想法.;)