恭喜你!您刚刚绕过编程语言/类型系统的范围,从您离开的地方到世界的另一端。您刚刚落在动态语言/基于原型的对象领域的边界上!
许多动态语言(例如JavaScript,PHP,Python)允许在运行时扩展或更改对象属性。
这种形式的极端形式是一种基于原型的语言,例如Self或JavaScript。严格来讲,他们没有课程。您可以执行看起来像具有继承的基于类,面向对象的编程的操作,但是与诸如Java和C#之类的更为清晰定义的基于类的语言相比,规则大大放松了。
像PHP和Python这样的语言存在于中间地带。他们有常规的,惯用的基于类的系统。但是可以在运行时添加,更改或删除对象属性,尽管有一些限制(例如“内置类型除外”),这些限制是您在JavaScript中找不到的。
这种动力的最大折衷是性能。忘了该语言的强弱输入类型,或将其编译成机器代码的能力。动态对象必须表示为灵活的地图/词典,而不是简单的结构。这增加了每个对象访问的开销。一些程序竭尽全力来减少这种开销(例如,使用幻像kwarg分配和Python中基于插槽的类),但是额外的开销通常仅与课程和入场费用相当。
回到您的设计,您正在将具有动态属性的功能嫁接到类的子集上。阿Product
可具有可变的属性; 大概是一个Invoice
或一个Order
将不会。这不是坏路。它使您可以灵活地在需要的地方进行更改,同时保持严格,有纪律的语言和类型系统。不利的一面是,您负责管理那些灵活的属性,您可能必须通过看起来与更多本机属性稍有不同的机制来进行管理。p.prop('tensile_strength')
而不是p.tensile_strength
,例如,和p.set_prop('tensile_strength', 104.4)
而不是p.tensile_strength = 104.4
。但是我已经使用Pascal,Ada,C,Java甚至是动态语言来开发了许多程序,并且这些程序对非标准属性类型完全使用了此类getter-setter访问方式。该方法显然是可行的。
顺便说一句,静态类型和高度变化的世界之间的这种张力非常普遍。在设计数据库架构时,尤其是对于关系和关系前数据存储,经常会遇到类似的问题。有时,可以通过创建“超级行”来解决该问题,该行应具有足够的灵活性以包含或定义所有想象的变体的并集,然后将出现在这些字段中的所有数据填充。在WordPress的wp_posts
表格,例如,有一个像场comment_count
,ping_status
,post_parent
和post_date_gmt
那些只有在某些情况下有趣的,而且在实践中往往变成空白。另一种方法是非常备用的标准化表格,例如wp_options
,就像Property
类。尽管它需要更明确的管理,但其中的项目很少为空白。面向对象和文档数据库(例如MongoDB)通常可以更轻松地处理更改选项,因为它们可以随意创建和设置属性。