命名类 - 如何避免将所有内容都称为 “<WhatEver> Manager”?

很久以前,我读过一篇文章(我相信是博客文章),这使我走在命名对象的 “正确” 轨道上:对程序中的命名要非常谨慎。

例如,如果我的应用程序是(作为一个典型的业务应用程序)处理的用户,公司和地址,我有一个User ,一个Company和一个Address域类 - 也许某处UserManager ,一个CompanyManagerAddressManager会弹出一个手柄那些事。

所以,你可以告诉那些UserManagerCompanyManagerAddressManager吗?不可以,因为 Manager 是一个非常通用的术语,适用于您可以使用域对象执行的所有操作。

我阅读的文章建议使用非常具体的名称。如果它是 C ++ 应用程序,并且UserManager的工作是分配用户并将其从堆中释放出来,则它将无法管理用户,但可以保护用户的生死。嗯,也许我们可以称其为UserShepherd

或者,也许UserManager的工作是检查每个 User 对象的数据并用密码对数据签名。然后我们有一个UserRecordsClerk

现在,这个想法一直困扰着我,我尝试应用它。并且很难找到这个简单的想法。

我可以描述这些类的作用,并且(只要我不会陷入快速而肮脏的编码中)我编写的类就是件事。从描述到名称,我想念的是一种名称目录,这是一个将概念映射到名称的词汇表。

最终,我想在脑海中想到一个模式目录(通常,设计模式很容易提供对象名称,例如工厂

  • 工厂 - 创建其他对象(取自设计模式的命名)
  • 牧羊人 - 牧羊人处理对象的生命周期,对象的创建和关闭
  • 同步器 - 在两个或多个对象(或对象层次结构)之间复制数据
  • 保姆 - 帮助对象在创建后达到 “可用” 状态 - 例如,通过连接到其他对象

  • 等等等

那么,您如何处理该问题?您是否有固定的词汇表,是否在动态地发明新名称或是否考虑将名称命名为不太重要或错误的?

PS:我也对讨论该问题的文章和博客链接感兴趣。首先,这是让我思考的原始文章: 不带 “管理器” 的 Java 类命名


更新:答案摘要

这是我同时从这个问题中学到的一些小知识。

  • 尽量不要创建新的隐喻(保姆)
  • 看看其他框架做什么

有关此主题的其他文章 / 书籍:

还有我从答案中(主观地!)收集的名称前缀 / 后缀的当前列表:

  • 协调员
  • 建造者
  • 作家
  • 读者
  • 处理程序
  • 容器
  • 协议
  • 目标
  • 转换器
  • 控制者
  • 视图
  • 实体

道路上的一个好提示:

不要让命名麻痹。是的,名称很重要,但它们的重要性还不足以浪费大量时间。如果您不能在 10 分钟内想到一个好名字,那就继续吧。

答案

我问了一个类似的问题 ,但是在可能的情况下,我尝试复制. NET 框架中已经存在的名称,然后在 Java 和 Android 框架中寻找想法。

似乎HelperManagerUtil是您为协调不包含状态且通常是过程性和静态性的类而附加的不可避免的名词。另一种方法是Coordinator

您可能会得到名称特别为紫色的 prosey,并且可以使用MinderOverseerSupervisorAdministratorMaster之类的名称,但是正如我所说,我更喜欢像以前使用的框架名称那样保留它。

您还可以在. NET 框架中找到一些其他常见的后缀(如果这是正确的术语):

  • Builder
  • Writer
  • Reader
  • Handler
  • Container

您可以看一下source-code-wordle.de ,我在那里分析了. NET 框架和其他一些库的类名最常用的后缀。

前 20 名是:

  • 属性
  • 类型
  • 帮手
  • 采集
  • 转换器
  • 处理程序
  • 信息
  • 提供者
  • 例外
  • 服务
  • 元件
  • 经理
  • 节点
  • 选项
  • 语境
  • 项目
  • 设计师
  • 基础
  • 编辑

我全都追求好名字,而且我经常写关于选择事物名称时要格外小心的重要性。出于同样的原因,在命名事物时,我也谨防隐喻。在最初的问题中,“factory” 和 “synchronizer” 看起来像是好名字。但是,“牧羊人” 和 “保姆” 却不是,因为它们是基于隐喻的 。您代码中的类实际上不能是一个保姆。您之所以称其为保姆,是因为它照顾其他事情,就像现实生活中的保姆照顾婴儿或孩子一样。在非正式的演讲中这是可以的,但在我看来,用代码命名类(必须由谁知道谁知道谁来维护)是不好的。

为什么?因为隐喻是与文化有关的,而且往往与个人有关。对您来说,命名一个班级 “保姆” 可能很清楚,但对于其他人来说可能并不那么清楚。除非您编写的代码仅供个人使用,否则我们不应该依赖于此。

在任何情况下,约定都可能构成或破坏隐喻。 “工厂” 本身的使用是基于一个隐喻,但是已经存在了一段时间了,并且在编程世界中目前是相当知名的,所以我想说它是安全的。但是,“保姆” 和 “牧羊人” 是不可接受的。

如果我们正确地模拟了现实世界,我们可以不用任何xxxFactoryxxxManagerxxxRepository类:

Universe.Instance.Galaxies["Milky Way"].SolarSystems["Sol"]
        .Planets["Earth"].Inhabitants.OfType<Human>().WorkingFor["Initech, USA"]
        .OfType<User>().CreateNew("John Doe");

;-)

听起来像是溜滑的东西,贴在 thedailywtf.com,“ManagerOfPeopleWhoHaveMortgages” 等上。

我想一个整体的 Manager 类不是很好的设计是正确的,但是使用'Manager' 也不错。代替 UserManager,我们可以将其细分为 UserAccountManager,UserProfileManager,UserSecurityManager 等。

“经理” 是个好词,因为它清楚地表明一个类并不代表现实世界中的 “事物”。 'AccountsClerk'- 我应该如何判断这是一个管理用户数据的类,还是代表某个人担任其工作的帐户文员?

由于您对这方面的文章感兴趣,因此您可能会对 Steve Yegge 的观点文章 “在名词王国中执行死刑” 感兴趣:

http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html

当我发现自己想在类名中使用ManagerHelper时,我认为它是一种代码味道,这意味着我尚未找到正确的抽象,并且 / 或者我违反了单一职责原则 ,因此重构并付出了更多努力进入设计通常会使命名容易得多。

但是,即使设计良好的类也不会(总是)自己命名,而您的选择部分取决于您要创建业务模型类还是技术基础结构类。

业务模型类可能很困难,因为它们在每个域中都是不同的。我经常使用某些术语,例如域中策略类的Policy (例如LateRentalPolicy ),但是这些LateRentalPolicy通常来自尝试创建可与业务用户共享的 “ 普遍存在的语言 ”,设计和命名类,以便它们模拟现实世界中的想法,对象,动作和事件。

技术基础结构类要容易一些,因为它们描述了我们非常了解的领域。我更喜欢将设计模式名称合并到类名称中,例如InsertUserCommand, CustomerRepository,SapAdapter.我了解关于传达实现而不是意图的担忧,但是设计模式将类设计的这两个方面结合在一起 - 至少在处理基础结构时,即使在隐藏细节的情况下,您也希望实现设计是透明的。

熟练使用(例如) GOF 书中定义的模式,并在命名这些对象后给我命名类,组织它们和传达意图的漫长道路。大多数人会理解这种命名法(或至少其中的大部分)。

如果我不能给我的类一个比 XyzManager 更具体的名称,这对我来说是重新考虑这是否是真正属于一个类的功能(即体系结构的 “代码味道”)的关键。

我认为要记住的最重要的事情是:名称是否具有描述性?您可以通过查看名称来告诉班级应该做什么吗?在类名中使用 “管理器”,“服务” 或 “处理程序” 之类的词可能被认为太笼统,但是由于许多程序员都在使用它们,因此也有助于理解该类的用途。

我自己经常使用外观模式(至少,我认为这就是所谓的)。我可以有一个仅描述一个用户的User类,以及一个跟踪我的 “用户集合” 的Users类。我不称该类为UserManager因为我不喜欢现实生活中的管理者,也不想让他们想起:) 简单地使用复数形式有助于我理解该类的作用。