假设我有一个与类/模型墙有关系的类/模型建筑物,并且又与类/模型窗口有关系,其形式是一个建筑物可以有很多表面,而一个表面可以有很多窗口(一个到另一个许多)。 现在,当我想向该建筑物添加窗口时,也许也仅向某些曲面添加窗口时,是否应该将函数(以及搜索函数/循环)写入模型内部?还是在模型或外部调用的单独类/脚本之外?
我可以想象,当功能是模型的一部分时,从长远来看,如果需要更改,可能会引起问题。
更清洁的体系结构/标准是什么,因为两者都可以工作? 如果可能的话,您可以给我一个资料,以进一步了解该特定问题吗?
在我的情况下,我将python和sqlalchemy和postgres一起使用,但是这个问题对于其他编程语言也可能是合法的。
(我希望这个问题不太广泛/基于观点)
答案 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
。使用您的方法state
,open_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)
对象时,该函数负责验证和限制。但是请记住,对模型的更改也必须反映在这些函数/类中。
我认为这两个选项均有效;无论您选择哪种方式,都要与您的决定保持一致。