【发布时间】:2021-02-12 07:58:57
【问题描述】:
在 MATLAB 中将类属性验证与抽象属性结合使用时会出现(对我而言)意外行为。这是一个涉及三个类的简短示例:
classdef TestClass
properties (Abstract)
aprop (1,1) TestClassB
end
end
classdef TestClassB
methods
function obj = TestClassB(a)
disp(a);
end
end
end
classdef TestClassC < TestClass
properties
aprop
end
end
然后,当尝试实例化 TestClassC 对象时,我收到以下错误:
>> TestClassC()
Error defining property 'aprop' of class 'TestClass'. Unable to construct default
object of class TestClassB.
显然,MATLAB 正在尝试在 TestClass 中实例化抽象属性 aprop,然后由于 aprop 的类定义 TestClassB 中缺少有效的零参数构造函数而失败。我意识到零参数构造函数问题在理论上是可以修复的(尽管只有当您有权修改 TestClassB 时),但 MATLAB 正在实例化一个抽象属性这一事实似乎很奇怪。维基百科关于抽象类型的文章的第一行字面意思是:
...抽象类型是主格类型系统中不能直接实例化的类型...
也许这是 MATLAB 作为弱类型语言实现属性验证的唯一方式,但这是一个不幸的结果。
附带说明,如果 TestClassB 有一个有效的零参数构造函数但被定义为抽象的,那么您最终会落入同一个陷阱,但会出现稍微不同的错误:
>> TestClassC()
Error defining property 'aprop' of class 'TestClass'. Class TestClassB is abstract.
Specify a default value for property aprop.
这种行为有充分的理由吗?
编辑:
额外的测试类观察
- 删除
TestClass中的大小验证可消除错误。显然,MATLAB 在没有有效的零参数构造函数的情况下初始化一个空对象数组是没有问题的。注意:这仅适用于TestClassB是非抽象的。 - 如果
TestClassB是抽象的并且TestClassC用TestClassB的具体子类在属性块中初始化aprop,则没有错误(假设具体子类具有有效的零参数构造函数)。注意:如果aprop在TestClassC的构造函数中被初始化,这不为真。
激励例子
上面的UML图是一个典型的继承与组合结合的例子。 GenericCar 和 GenericEngine 是抽象类。 GenericCar 包含 GenericEngine,但 Racecar 将其引擎指定为具体的 V8(其中“isa”GenericEngine)。不幸的是,这不能在 MATLAB 中使用属性验证来构造,因为 MATLAB 不允许您重新定义抽象属性的类,即使它是原始定义的子类。
假设您接受不能将Racecar 中的engine 定义为V8。即便如此,如果您没有为engine 提供初始值在Racecar 的属性块 中,MATLAB 在创建 Racecar 对象时会抛出错误,因为它会尝试初始化 @987654353 @ 使用抽象类型GenericEngine。即使Racecar 的构造函数将引擎初始化为V8 对象也是如此。 这突出了属性验证和对象实例化之间的奇怪联系。
【问题讨论】:
-
“这突出了属性验证和对象实例化之间的奇怪联系。”但我认为这是有道理的。如果一个属性不能是
[],但必须是GenericEngine,那么当对象被实例化时,它必须有一个GenericEngine作为属性。否则 MATLAB 应该做什么?如果属性验证是您所追求的,为什么不 (1) 制作一个验证值的 setter,或者 (2) 将属性设为只读,在构造函数中设置并且永不更改? -
顺便说一下,您在此处尝试执行的继承类型在 MATLAB 中毫无意义。 MATLAB 不是强类型语言,除了继承行为之外不需要使用继承(检查他们如何实现句柄基类和类似类)。您可以更简单地构建代码,不需要
engine是抽象类GenericEngine的子类,但要求它具有特定的行为(它实现某些功能)。 -
PS:要验证一个对象在您的 setter 函数中是否具有所需的方法,请使用
ismethod。 -
@CrisLuengo 老实说,我不确定 MATLAB 应该做什么。也许将属性留空并仅在实际设置属性时应用验证?当然,这也需要权衡取舍,例如用不严格有效的属性实例化一个对象。或者,它至少可以在构造函数执行之前推迟验证属性,但这可能也会产生副作用。至于变通方法,我同意还有其他可能不太“直接”的方法来实现相同或相似的结果,但是属性验证的意义何在?
-
@CrisLuengo 您提出了一些关于如何在 MATLAB 等弱类型语言中最好地使用 OOP 的有趣观点。你能指出我提到的关于句柄基类的信息吗?至于要求特定行为而不是使用抽象类,这不正是抽象类的用途,定义了必须实现的方法吗?似乎手动检查对象中的方法名称是实现相同功能的一种迂回方式。
标签: matlab validation oop abstract abstract-data-type