命名类-如何避免将所有内容称为“<What的>管理器”?

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

例如,如果我的应用程序(作为一个典型的商业应用程序)处理用户,公司和地址,我将有一个User,一个Company和一个Address域类-可能在某个地方会弹出UserManagerCompanyManagerAddressManager来处理这些事情。

那么你能说出那些UserManagerCompanyManagerAddressManager是做什么的吗?不,因为Manager是一个非常通用的术语,适用于你可以用域对象做的任何事情。

我读到的文章建议使用非常具体的名称。如果它是一个C++应用程序,UserManager的工作是分配和释放用户从堆中,它不会管理用户,而是保护他们的出生和死亡。嗯,也许我们可以称之为UserShepherd

或者UserManager的工作是检查每个User对象的数据并对数据进行加密签名。然后我们会有一个UserRecordsClerk

现在这个想法一直困扰着我,我试着应用它。发现这个简单的想法非常困难。

我可以描述类做了什么,(只要我不陷入快速和肮脏的编码)我编写的类完全做了一个的事情。从描述到名称,我错过的是一种名称目录,一个将概念映射到名称的词汇。

最终,我希望在我的脑海中有一个类似于模式目录的东西(通常设计模式很容易提供对象名称,例如工厂

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

  • 等等等等。

那么,你是如何处理这个问题的呢?你是否有固定的词汇,你是否会在工作中发明新的名字,或者你是否认为命名不那么重要或错误?

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


更新:答案摘要

以下是我从这个问题中学到的一点总结。

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

关于此主题的更多文章/书籍:

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

  • 协调员
  • Builder
  • 作家
  • 读者
  • 处理程序
  • 容器
  • 议定书
  • 目标
  • 转换器
  • 控制器
  • 查看
  • 工厂
  • 实体
  • 水桶

在路上有一个很好的提示:

不要给瘫痪命名。是的,名字非常重要,但它们还不够重要,不足以浪费大量时间。如果你不能在10分钟内想出一个好名字,那就继续。

288884 次浏览

熟悉由(比如)GOF书定义的模式,并以这些模式命名对象,让我在命名类、组织类和传达意图方面有了很大的帮助。大多数人会理解这个命名法(或者至少是它的主要部分)。

我觉得最关键的一点是在代码可见范围内保持一致,也就是说,只要所有需要看你代码的人都理解你的命名规范,那么没问题,即使你决定叫他们‘CompanyThingamabob’或者‘UserDoohikey’。如果你在一家公司工作,第一步是看看是否有公司命名规范。如果没有,或者你不在一家公司工作,那就用你觉得合理的术语创建自己的命名规范,把它传递给几个值得信赖的同事/朋友,他们至少会随便编码,然后融入任何有意义的反馈。

应用别人的惯例,即使它被广泛接受,如果它没有从页面上跳下来,在我的书中是一个错误。首先,最重要的是,我需要在不参考其他留档的情况下理解我的代码,但同时它需要足够通用,以至于在同一行业的同一领域的其他人也不会无法理解。

我会考虑您为系统使用的模式,类的命名约定/编目/分组往往由所使用的模式定义。就个人而言,我坚持这些命名约定,因为它们是其他人能够拿起我的代码并运行它的最有可能的方式。

例如,UserRecordsClerk可能更好地解释为扩展了一个通用的RecordsClerk接口,UserRecordsClerk和CompanyRecordsClerk都实现了这个接口,然后专门研究它,这意味着人们可以查看接口中的方法,看看它的子类通常做什么。

请参阅设计模式之类的书以获取信息,这是一本很棒的书,可能会帮助您明确您的代码的目标-如果您还没有使用它!; o)

我认为,只要您的模式选择得当,并在适当的范围内使用,那么相当没有创意的简单类名就足够了!

具体到C#,我发现“框架设计指南:可重用的约定、习语和模式。NET库”有很多关于命名逻辑的好信息。

至于找到那些更具体的单词,我经常使用同义词库并跳过相关单词试图找到一个好的。尽管我尽量不花太多时间在它上面,但随着我在开发中的进步,我想出了更好的名字,或者有时意识到SuchAndSuchManager真的应该被分解成多个类,然后那个被弃用的类的名字就变成了一个问题。

我觉得最重要的一点是:这个名字有足够的描述性吗?看名字就能知道这个类是做什么的吗?在类名中使用“Manager”、“Service”或“Handler”这样的词可能会被认为太通用了,但由于很多程序员使用它们,这也有助于理解这个类是做什么的。

我自己也经常使用门面模式(至少,我认为这就是它的名称)。我可以有一个User类只描述一个用户,一个Users类跟踪我的“用户集合”。我不称这个类为UserManager,因为我不喜欢现实生活中的经理,我不想被提醒他们:)简单地使用复数形式有助于我理解这个类的作用。

这听起来像是一个滑坡,会发布在thedailywtf.com上,“ManagerOfPeopleWhoHazeMortgages”等。

我想一个单一的Manager类是不好的设计,但使用“Manager”也不错。我们可以将其分解为UserAccountManager、UserProfileManager、UserSecurityManager等,而不是UserManager。

“Manager”是一个好词,因为它清楚地表明一个类不代表现实世界中的“事物”。“AccountsClerk”——我该如何判断这是一个管理用户数据的类,还是代表某人是他们工作的会计文员?

我完全赞成起个好名字,我经常写关于在为事物选择名称时非常小心的重要性。出于同样的原因,我在命名事物时对隐喻持谨慎态度。在最初的问题中,“工厂”和“同步器”看起来像是好名字,因为它们的含义是好名字。然而,“牧羊人”和“保姆”不是,因为它们是基于隐喻的。你代码中的一个类不可能是字面上保姆;你称之为保姆是因为它照顾其他一些东西,非常像现实生活中的保姆照顾婴儿或孩子。这在非正式演讲中是可以的,但在我看来,在代码中命名类是不可以的,这些代码必须由谁知道谁知道什么时候维护。

为什么?因为隐喻依赖于文化,通常也依赖于个人。对你来说,命名一个类为“保姆”可能非常清楚,但也许其他人不太清楚。我们不应该依赖于这一点,除非你正在编写仅供个人使用的代码。

在任何情况下,惯例都可以创造或破坏一个隐喻。“工厂”的使用本身就是基于一个隐喻,但是这个隐喻已经存在了很长一段时间,目前在编程世界中相当知名,所以我认为使用它是安全的。然而,“保姆”和“牧羊人”是不可接受的。

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

似乎HelperManagerUtil是不可避免的名词,用于协调不包含状态并且通常是过程和静态的类。另一种选择是Coordinator

您可以使用名称获得特别紫色的Prosey,并使用MinderOverseerSupervisorAdministratorMaster之类的东西,但正如我所说,我更喜欢保持它像您习惯的框架名称一样。


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

  • Builder
    使用一些参数来构造特殊类型实例的类型。Builder通常是一次性的。它甚至可能不需要分配变量。
    如果类型需要重复创建对象,请使用Factory
    如果类型负责创建多个不同类型的对象,请使用Factories
  • Writer
    将一些变量写入某物。
  • Reader
    读取变量。
  • Handler
    为了处理某种情况或某事而设计的。
  • Container
    可以把东西放进去。

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

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

;-)

当我发现自己考虑在类名中使用ManagerHelper时,我认为这是一种代码气味,这意味着我还没有找到正确的抽象和/或我违反了单一责任原则,所以重构和在设计中投入更多精力通常会使命名变得更容易。

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

业务模型类可能很难,因为它们对每个领域都是不同的。我经常使用一些术语,比如Policy用于域内的策略类(例如LateRentalPolicy),但这些通常来自于尝试创建一个“泛在语言”,你可以与业务用户共享,设计和命名类,以便他们对现实世界的想法、对象、操作和事件进行建模。

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

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

前20名是:

  • 属性
  • 类型
  • 助手
  • 收藏
  • 转换器
  • 处理程序
  • 信息
  • 提供商
  • 例外
  • 服务
  • 元素
  • 经理
  • 节点
  • 选项
  • 工厂
  • 背景
  • 项目
  • 设计师
  • 基地
  • 编辑器

如果我不能为我的类想出一个比XyzManager更具体的名字,这将是我重新考虑这是否真的是属于一个类的功能,即架构的“代码气味”。