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


1188

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

例如,如果我的应用程序(作为典型的业务应用程序)正在处理用户,公司和地址,则我将具有User,a CompanyAddress域类-可能会弹出a UserManager,a CompanyManager和a AddressManager来处理这些问题。

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

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

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

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

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

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

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

  • 等等等

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

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


更新:答案摘要

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

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

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

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

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

道路上的一个好提示:

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


11
它属于社区Wiki,因为没有一个“最佳”答案。这是一个讨论。
DOK

13
那是反直觉的。他们不应该称之为论坛吗?我认为维基只用于收集事实,而不是观点。
AaronLS

78
感谢您保持更新-但是,最后一个提示是可怕的建议!如果您在10分钟内想不出一个好名字,则您的课程可能有问题。(标准警告:1)完美是善的敌人,2)运输是一项功能-请记住,您承担技术债务。)
Jeff Sternal 2010年

11
如果您无法在10分钟内想到一个好名字,请向您的同事寻求帮助。不要只是放弃。

9
如果您不能在10分钟内想到一个好名字,请尝试向您的同事解释;他们可能会想到一个好名字(user338195),但是尝试解释一个好名字可能会帮助您发现它的毛病(Jeff)。
WillC '16

Answers:


204

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

似乎HelperManagerUtil是您为协调类所附加的不可避免的名词,这些类不包含状态并且通常是过程性的和静态的。另一种选择是Coordinator

你可以得到与名字特别紫色prosey,去之类的东西MinderOverseerSupervisorAdministrator,和Master,但正如我所说,我更喜欢保持它就像你正在使用的框架名称。


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

  • Builder
  • Writer
  • Reader
  • Handler
  • Container

4
我非常喜欢这些。它们不会陷入不良或未知隐喻的陷阱,因为.NET Framework已在使用它们。查看其他库(Java)可能也很有趣,以便更多地输入常用的库。
froh42 2010年

我想建议Conductor一下,就像一个乐团的指挥一样。当然,这是一个重要角色,具体取决于您需要“进行”的协作的性质(其他对象是非常专业的参与者,应该对集中式命令做出反应,而不必为其他任何协作者担心太多)。
heltonbiker 2015年

1
我不认为-er类的解决方案是使用不同的名称。正如我在许多其他文章中所读并试图了解的答案一样,您需要更改架构,而不仅仅是使用的名称。
Michael Ozeryansky '19

115

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

前20名是:

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

147
很久以前,在一个特定的公司中,我知道一位工程师对这样荒谬且不断增长的后缀规则感到厌倦,这些规则困扰着该公司,因此他竭尽全力地结束了每一堂课Thingy

8
没有应使用后缀的上下文,此名称列表本身并没有那么有用。
弗雷德(Fred)

65

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

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

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


10
这个论点的确破裂了,因为显然Factory本身就是一个隐喻。通常,隐喻会真正弄清对象可能擅长的方面,而模糊或泛泛会自动确保弄清楚代码的作用的唯一方法就是充分阅读代码!最坏的情况。
Kzqai

1
+1避免使用“可爱”名称。我认为与语言尽可能直接地沟通是很棒的。(当然,同时做到直接,简洁,准确明确并不总是容易的……)
andrewf '18

1
对于具体的类,动词+“ er”的创造性选择通常比五颜六色的类比要清楚。另一方面,新的抽象-一种新概念,一种新的“事物”,而不仅仅是一种新的“事物”-通常可以很好地用作隐喻(Java的“ beans”,Haskell的“ lenses”,GUI “窗口”,许多语言的“承诺”)。但是,大多数代码库都不会有任何真正的发明。
Malnormalulo

51

我们可以做没有任何xxxFactoryxxxManager或者xxxRepository类,如果我们正确地模拟现实世界中:

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

;-)


11
您将如何获得平行宇宙和替代维度?
tster

23
这很容易:Omniverse.Instance.Dimensions [“ Ours”]。Universes [“ Ours”]。Galaxies ... ...好的,好的,我承认这需要重新编译。;-)
herzmeister 2010年

73
更新::这是在.NET 4.0中加入Universe.Instance.ToParallel());
康奈尔

2
虽然违反了得墨meter耳定律!
乔纳斯·格兰杰

13
这些是对象和成员,而不是类名称
Harry Berry

39

听起来像是滑到要在thedailywtf.com,“ ManagerOfPeopleWhoHaveMortgages”等上发布的内容上。

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

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


8
那么UserAccounter,UserProfiler和UserSecurer呢?如果您放弃了Manager,则必须提出具体的定义,我认为这是一件好事。
Didier A.

10
那么UserAccount,UserProfile,UserSecurity oO呢?
风土

3
我将其命名为“ MortageOwnersManager”
volter9 2014年

有时域具有特定名称。像“ MortageHolder”一样,可能比“ MortageOwner”更好
borjab 16-10-13


24

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

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

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

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


1
我非常喜欢对Policy包含业务逻辑的类使用后缀的想法
jtate

+1表示与“ Manager”和“ Helper”之类的名称相关的代码气味。我发现,如果我没有明确的名称,通常至少部分是由于我对业务领域或技术领域的理解有些模糊。几乎等效地,这可能意味着我只是在被动地分解类,因为它们“太大”了-对我来说,这也是建模不足的迹象。这应该是票数最高的答案。
nclark

10

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


福勒对我来说是一个很好的参考,但GOF是一个很好的建议。
拉撒路

原谅我的无知。您指的是哪本福勒书?
Brian Agnew


19
嗯,有时候这行得通(例如像工厂或策略),但是在其他时候,我觉得这确实比类的意图和工作传达了实现的方式(我使用过模式!)。例如,Singleton最重要的是它代表的是什么,而不是它是Singleton。因此,严格命名使用的模式就像严格命名使用的类型。例如,匈牙利符号被Windows系统组误用(描述C数据类型而不是“意图类型”)
froh42

1
对于技术基础结构类,通常需要使实现透明化-并且大多数规范的设计模式名称都传达实现和意图。但是,领域模型类是另一回事。
杰夫·斯坦恩

10

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


8

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

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


我也非常喜欢这种方法,因为它简化了自上而下管理对象的想法。一组用户更可能暗示工作是在用户之间完成的,而不是从UserManager向下进行。同样,拥有用户对用户的引用并不像拥有UserManager那样奇怪。它比相对的想法更开放,而不是严格的面向对象。
Seph Reed

这种方法的问题在于,很难在代码中搜索Users,尤其是当您传递管理器对象时。this.users = new Users()但是,您代码中的其他地方总是users会引用Users 数组。
雪人

正如您所说的,用户确实暗示着“用户集合”-状态实体的集合。但是SRP意味着您不想将用户管理(功能和业务逻辑)与用户数据(状态)捆绑在一起。并不是说您错了,如果类负责管理用户,而不仅仅是存储用户的状态和基本CRUD,那么UserManager就适用。
理查德·摩尔

5

特定于C#,我发现“框架设计指南:可重用.NET库的约定,惯用语和模式”在命名逻辑方面有很多很好的信息。

至于找到那些更具体的单词,我经常使用同义词库并跳过相关的单词来尝试找到一个好的单词。但是,我尽量不花很多时间,因为在开发过程中我会想到更好的名称,或者有时意识到SuchAndSuchManager应该将其真正拆分为多个类,然后不赞成使用的类的名称就不再是问题了。 。


3

我相信这里的关键是要在代码可见性范围内保持一致,即,只要需要查看代码或在代码上工作的每个人都了解您的命名约定,那么即使您决定调用它们,也应该很好“ CompanyThingamabob”和“ UserDoohickey”。如果您在一家公司工作,那么第一站就是查看公司是否有命名约定。如果没有或您不在一家公司工作,则使用对您有意义的术语来创建自己的术语,将其传递给一些值得信赖的同事/朋友,这些同事/朋友至少要随意编写代码,并合并所有有意义的反馈。

即使在别人的约定被广泛接受的情况下,应用它的约定,即使它不能使您脱颖而出,这也是我书中的一个错误。首先,我需要在不参考其他文档的情况下理解我的代码,但是同时,它必须足够通用,以至于对于同一行业中相同领域的其他人而言,这是不可理解的。


1
尽管如此,一致的,甚至有点不直观的约定比仅开始自己的约定要好。工作在项目上的人们将很快学会任何一致的约定,很快就会忘记该功能与乍一看并不完全一样。
男孩先生2009年

@约翰,这就是我所说的。该约定需要被小组接受,如果您在公司工作,请查看是否存在公司约定。对于公司,我正在考虑任何团队,无论是开源项目团队还是散落的程序员集合。如果每个人都选择了几乎可以满足他们要求的可用产品,那么我认为我们将非常缺乏创新。
拉撒路

2

我会考虑您在系统上使用的模式,命名约定/编目/趋势类别的分组往往由所使用的模式定义。我个人遵循这些命名约定,因为它们是另一个人获取我的代码并运行它的最可能方式。

例如,最好将UserRecordsClerk解释为扩展一个通用的RecordsClerk接口,该接口由UserRecordsClerk和CompanyRecordsClerk都实现并专门研究,这意味着可以查看接口中的方法以查看其子类的用途/通常用途。

请参阅诸如Design Patterns之类的书以获取信息,这是一本非常出色的书,它可能会帮助您弄清代码的目标用途-如果您还没有使用它的话!; o)

我认为,只要适当地选择和使用了您的模式,那么相当简单的类名就足够了!


我在Brian Agnew的回答中对此进行了评论。我认为模式名称仅在某些情况下(工厂,策略)而不是在其他情况下(Singleton)才是好的类名称。我希望名称能反映班级的工作,而不是我的实现方式。
froh42
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.