在模型内部还是外部将嵌套数据添加到模型的功能?

时间:2018-08-30 09:01:17

标签: python postgresql sqlalchemy

假设我有一个与类/模型墙有关系的类/模型建筑物,并且又与类/模型窗口有关系,其形式是一个建筑物可以有很多表面,而一个表面可以有很多窗口(一个到另一个许多)。 现在,当我想向该建筑物添加窗口时,也许也仅向某些曲面添加窗口时,是否应该将函数(以及搜索函数/循环)写入模型内部?还是在模型或外部调用的单独类/脚本之外?

我可以想象,当功能是模型的一部分时,从长远来看,如果需要更改,可能会引起问题。

更清洁的体系结构/标准是什么,因为两者都可以工作? 如果可能的话,您可以给我一个资料,以进一步了解该特定问题吗?

在我的情况下,我将python和sqlalchemy和postgres一起使用,但是这个问题对于其他编程语言也可能是合法的。

(我希望这个问题不太广泛/基于观点)

1 个答案:

答案 0 :(得分:1)

对于初学者来说,我认为最好在Softwareengineering中提出这个问题。但是,我不妨为此给你几分钱。

通常,这取决于...

通常,encapsulation是面向对象编程中的核心概念之一。 对对象状态的任何更改都应由对象本身完成(尽管可能从外部触发),因此应保证遵守为对象定义的条款和条件。对象的行为应在对象内部而不是外部实现。

您不想公开展示Window的属性wall,以使全世界都能直接访问它。您想将其隐藏在getter和setter后面。如果说Window恰好是“内部”,则您希望Wall拒绝放置在传递到wall设置器的Wall上。您不希望Person对象将Window的{​​{1}}从'open'更改为'close',反之亦然,您希望state调用Person的{​​{1}}响应。 Window方法,例如以确保内部关闭的窗口不会再次关闭。

此外,隐藏实现细节可以帮助维护您的界面并使对类的更改透明。举例来说,您决定,除了禁止使用内墙之外,现在还希望防止将“普通”窗户放入地下室的外墙中。您可以在open()的现有close()设置器中执行该检查,并且外部代码的唯一可见更改将是拒绝的另一个潜在原因(“ wall = normal and wall = basement” =“ interior”)。或者,您想添加一个表示wall清洁状态的属性,并在新的Window和旧的'open'/'close'Window之间进行适当的区分,您想将旧属性重命名为cleanliness_state。使用您的方法stateopen_close_state(可能还有open()close())读取和写入您的'open'/'close'is_open()属性,更改只会影响您的类实现,而不是使用它的每一段代码。

但是!

您可能有一些类只能作为某种集合使用,即data classes。它们几乎没有实现任何功能,并公开公开了它们的属性以供全世界读取和写入,因此广泛忽略了封装的概念。有人可能会说,在对象关系映射层(例如SQLAlchemy)中实现的类/模型比在OOP意义上的对象更多的是数据对象/数据类,尤其是在主要用于持久化和检索结构化数据时。外部代码更改此类对象的状态或实现其功能并不罕见,例如Django框架中使用自己的ORM层来实现和持久化模型的视图。

那么?

它归结为您的具体案例。您已经提到过要考虑限制窗户的放置。可能基于所涉及的窗户和墙壁的属性。

如果您考虑使用SQLAlchemy模型不仅仅是一种持久化对象的方法,请继续在模型中实施行为并更改逻辑。但请记住,a)您最终可能会与模型的基类的方法/属性产生冲突,b)模型的属性必须保持公开状态,以维护ORM层的功能(尽管SQLAlchemy可能可以工作)具有只要定义了getter和setter的属性;我从未测试过。)

如果您希望模型成为保存和检索结构化数据的便捷方法,请保持模型整洁,并使用一些实用程序功能或类来实现对象的行为,并确保在代码中使用它们时的约定;例如拥有一个函数is_closed(),当您尝试在state的{​​{1}}属性上引用place_window_on_wall(window: Window, wall: Wall)对象时,该函数负责验证和限制。但是请记住,对模型的更改也必须反映在这些函数/类中。

我认为这两个选项均有效;无论您选择哪种方式,都要与您的决定保持一致。