面向对象编程 - 使用对象管理器还是不使用?

10

有一个架构风格的问题,我想请您发表意见:

我的ORM给我提供了一个User对象,对应于我的系统中的一个用户。我想为处理用户开发一堆方法 - GetByUsername()、Authenticate()、VerifyLoginPassword()等等。然而,我感觉其中一些方法并不真正属于User类 - 例如GetByUsername()至少感觉像是User类的静态方法,但使用另一个类,比如"UserManager",来提供这些用户管理类型的任务更加“干净”一些吗?例如,如果进行身份验证的是安全系统,那么将Authenticate()方法包含在User实例中似乎有点奇怪?

我担心的是,我按照这种模式,最终User类只是一个结构体,而我的User Manager和Security Manager类实际上会完成所有方法工作。让这些管理器类操作轻量级对象并不是非常“面向对象”。

欢迎您就这个哲学问题发表您的想法或提供相关先前文章的链接!

7个回答

6

看起来你已经超越了将对象定义为"一只狗是一个动物"并开始从角色、责任和行为方面定义对象。

我建议阅读这本书,帮助你进行这个转换并真正“领悟它”:

对象设计:角色、责任和协作

我无法回答你的具体问题,因为这是一个非常基础的设计决策,你应该学习“更广阔的视野”。这本书会为你提供责任驱动设计的原则和技巧方面的良好基础。


3

Martin Fowler有一些关于这个问题的有用观点

基本选择在于服务定位器和依赖注入。首先,这两种实现都提供了天真示例中缺失的基本解耦 - 在两种情况下,应用程序代码都独立于服务接口的具体实现。这两种模式之间的重要区别在于如何将该实现提供给应用程序类。使用服务定位器,应用程序类通过向定位器发送消息来显式请求它。使用注入时,没有显式请求,服务出现在应用程序类中 - 因此控制反转。

控制反转是框架的常见特征,但这是以一定代价为代价的。它往往很难理解,并且在尝试调试时会导致问题。因此,总的来说,除非我需要它,否则我更喜欢避免使用它。这并不是说它是坏事,只是我认为它需要证明自己比更直接的替代方案更好。


3

让所有这些管理类操作轻量级对象似乎不太符合"OO"的感觉。

我不知道这是否非常符合"OO",但对我来说,它感觉非常像MVC和关注点分离。拥有非常轻量级的业务类(仅仅是数据容器),然后使用移动它们的存储库对象是一种常见的模式。


1

你可以继续将所有功能从User类中重构出来,但正如你所说,最终可能什么都剩不下。此时,你可以选择评估你创建的所有其他类,然后针对每个类进行个别判断,决定是否这些类包含足够的功能以证明需要一个全新的类。

如果你决定一些类太小,那么你可以将它们的功能放回到User类中。例如,在User上拥有Validate函数而不是只在UserValidation类上拥有一个方法,我认为也没有什么问题。


1

我认为你说的那些方法可能不属于用户对象是正确的。Get/Search/Save 方法可以有争议,但我认为它们不应该在业务对象本身上实现,而应该使用 Repository(仓储模式),或者通过 查询对象 来实现,如果您不希望在仓储中抽象出 ORM。

至于身份验证,最好有一组负责身份验证的类,并将其从用户对象中剥离出来。这组类可以知道用户对象,或者更好的做法是它们应该知道一个契约,比如凭据。


0

我喜欢用另一种方式表达这个想法。由于没有涉及到任何业务逻辑,这些方法并不真正属于该领域。我想使用命令和查询分离原则。

GetByUsername() -- 这是一个查询,真的不需要任何业务逻辑。

Authenticate()、VerifyLoginPassword() -- 这些是验证逻辑,不应该在领域中完成。请参考这份文档 领域中基于集合的验证


0
您所描述的情况与对象是否遵循自服务或适配器模式来保存到存储库(即数据库)有关。
自服务将使对象自己保存,例如myObjectInstance.Save(),而适配器模式则是myObjectAdapter.Save(myObjectInstance)
适配器形式通常更受青睐,因为它可以将任何存储库功能从对象中移除。

为什么称其为适配器?它与适配器模式有什么共同之处吗? - Pavel Feldman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接