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

fro*_*h42 1147 oop naming design-patterns naming-conventions

很久以前我读过一篇文章(我相信一篇博客文章),它让我在命名对象的"正确"轨道上:非常谨慎地命名程序中的东西.

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

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

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

或者可能UserManager的工作是检查每个User对象的数据并以加密方式对数据进行签名.然后我们有一个UserRecordsClerk.

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

我可以描述这些类的功能和(只要我不进入快速和脏编码)我写的类只做件事.我想念从名称到名称的是一种名称目录,一种将概念映射到名称的词汇表.

最终,我想在我的脑海里有类似图案目录的东西(通常设计图案很容易提供对象名称,例如工厂)

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

  • 等等

那么,你如何处理这个问题呢?你有一个固定的词汇表,你是否动态发明新的名字,或者你认为命名的东西不是那么重要或错误?

PS:我也对链接​​到讨论这个问题的文章和博客感兴趣.首先,这是让我思考它的原始文章:在没有"经理"的情况下命名Java类


更新:答案摘要

以下是我在此期间从这个问题中学到的内容的一些总结.

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

关于这个主题的进一步文章/书籍:

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

  • 协调员
  • 生成器
  • 作家
  • 读者
  • 处理器
  • 容器
  • 协议
  • 目标
  • 变流器
  • 调节器
  • 视图
  • 实体

这条道路的好建议:

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

Chr*_*s S 194

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

它似乎HelperManager,并且Util是您为协调不包含状态的类而附加的不可避免的名词,并且通常是程序性的和静态的.另一种选择是Coordinator.

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

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

  • Builder
  • Writer
  • Reader
  • Handler
  • Container

  • 我非常喜欢这些.它们不会陷入糟糕或未知隐喻的陷阱,因为它们已经被.NET Framework使用.查看其他库(Java)也可能很有趣,以获得对常用内容的更多输入. (4认同)
  • 我不认为 -er 类的解决方案是想出一个不同的名称。正如我在许多其他帖子中读到的那样,并且我试图了解答案,您需要更改架构,而不仅仅是使用的名称。 (2认同)
  • 人们很容易过度考虑要使用的名称,这是一种反模式。 (2认同)

Mar*_*yer 112

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

前20名是:

  • 属性
  • 类型
  • 帮手
  • 采集
  • 变流器
  • 处理器
  • 信息
  • 提供商
  • 例外
  • 服务
  • 元件
  • 经理
  • 节点
  • 选项
  • 上下文
  • 项目
  • 设计师
  • 基础
  • 编辑

  • 很久以前,在一家特定的公司,我认识一位工程师如此厌倦了荒谬和越来越多的后缀规则,这些规则困扰着公司,他以"Thingy"的方式挑战每一堂课. (138认同)
  • 如果没有应用后缀的上下文,这个名称列表本身并没有那么有用. (7认同)

Ces*_*Gon 63

我都是为了好名字而且我经常写下在选择名字时要特别小心的重要性.出于同样的原因,在命名事物时我对隐喻很谨慎.在最初的问题中,"工厂"和"同步器"看起来就像它们似乎意味着的好名字.然而,"牧羊人"和"保姆"不是,因为它们是基于隐喻.在你的代码的类不能从字面上保姆; 你称之为保姆,因为它照顾其他一些非常像现实生活的保姆照顾婴儿或小孩.这在非正式演讲中是可以的,但不是(在我看来)可以在代码中命名类,这些代码必须由谁知道谁知道何时知道.

为什么?因为隐喻是文化依赖的,并且通常也是个人依赖的.对你来说,命名一个班级"保姆"可以非常清楚,但也许对其他人来说并不是那么清楚.除非您编写的代码仅供个人使用,否则我们不应该依赖它.

在任何情况下,惯例都可以成就或破坏隐喻."工厂"本身的使用是基于一个比喻,但它已经存在了很长一段时间,并且目前在编程世界中是众所周知的,所以我认为使用它是安全的.然而,"保姆"和"牧羊人"是不可接受的.

  • +1用于避免对其他人来说难以理解的隐喻 (12认同)
  • 这个论点真的打破了,显然工厂本身就是一个比喻.隐喻通常会清除对象可能擅长的内容,而模糊或通用自动确保通过完全阅读它来找出代码所做的唯一方法!最糟糕的情况. (10认同)

her*_*ter 49

如果我们正确地模拟现实世界xxxFactory,我们可以没有任何xxxManagerxxxRepository类别:

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

;-)

  • **更新:**这是在.NET 4.0中添加的:`Universe.Instance.ToParallel()`;) (72认同)
  • 这很简单:Omniverse.Instance.Dimensions ["我们的"].宇宙["我们的"].星系......好吧我承认这需要重新编译.;-) (21认同)
  • 您将如何获得并行Universe和备用维度? (10认同)
  • 那些是对象和成员,而不是类名 (10认同)
  • 虽然违反了得墨meter耳定律! (2认同)

Mr.*_*Boy 38

对于会发布在thedailywtf.com,"ManagerOfPeopleWhoHaveMortgages"等上的内容,这听起来像是一个滑坡.

我认为一个单一的Manager类不是好设计是正确的,但使用'Manager'并不错.我们可能会将其分解为UserAccountManager,UserProfileManager,UserSecurityManager等,而不是UserManager.

"经理"是一个好词,因为它清楚地表明一个阶级并不代表现实世界的"事物".'AccountsClerk' - 我该如何判断这是一个管理用户数据的类,还是代表某个职员的工作人员?

  • UserAccount,UserProfile,UserSecurity oO怎么样? (10认同)
  • UserAccounter,UserProfiler和UserSecurer怎么样?如果你摆脱了经理,你被迫提出具体的定义,我认为这是一件好事. (7认同)
  • 我会把它命名为"MortageOwnersManager" (3认同)

stu*_*ith 25

由于你对这个领域的文章感兴趣,你可能会对Steve Yegge的观点文章"名词王国的执行"感兴趣:

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


Jef*_*nal 21

当我发现自己在考虑使用ManagerHelper在类名中时,我认为这是一种代码味道,这意味着我还没有找到正确的抽象和/或我违反了单一责任原则,所以重构并在设计上付出更多努力经常使命名更容易.

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

业务模型类可能很难,因为它们对于每个域都是不同的.有一些方面,我用了很多,比如Policy为战略类域(例如,在LateRentalPolicy),但这些通常是试图建立一个"流动的通用语言 ",你可以与商业用户共享,设计和命名类,使他们模拟现实 - 世界的想法,对象,行动和事件.

技术基础设施类更容易,因为它们描述了我们非常熟悉的域.我更喜欢将设计模式名称合并到类名中,InsertUserCommand, CustomerRepository,或者SapAdapter.我理解关于沟通实现而不是意图的关注,但设计模式与类设计的这两个方面相结合 - 至少在你处理基础设施时,你想要的即使在隐藏细节时,实现设计也是透明的.


Bri*_*new 10

GOF书中所定义的模式相关,以及在这些模式之后命名对象在命名类,组织它们和传达意图方面有很长的路要走.大多数人会理解这种命名法(或至少是其中的一个主要部分).

  • 嗯,有时这很有效(例如像工厂或战略),但在其他时候我觉得这确实传达了实现的方式(我使用了模式!)而不是类的意图和工作.例如,单身人士最重要的是它代表什么 - 而不是单身人士.在使用的模式之后如此严格的命名感觉就像在使用的类型之后严格命名.例如,Windows系统组错误应用匈牙利表示法(描述C数据类型而不是"意图类型") (19认同)

Jas*_*sch 10

如果我不能为我的类提出比XyzManager更具体的名称,那么我将重新考虑这是否真的是一个属于一个类的功能,即一个架构的"代码味道".


Dro*_*zle 8

我认为最重要的是要记住:名称是否足够描述?你能看一下这个名字应该做什么吗?在类名中使用"经理","服务"或"处理程序"等词语可以被认为过于通用,但由于许多程序员使用它们,因此也有助于理解类的用途.

我自己一直在使用外观模式(至少,我认为这就是所谓的).我可以有一个User只描述一个用户的Users类,以及一个跟踪我的"用户集合"的类.我不打电话给班级UserManager因为我不喜欢现实生活中的经理而且我不想被提醒他们:)简单地使用复数形式可以帮助我理解班级的作用.

  • 这种方法的问题是,在代码中搜索“Users”变得非常困难,特别是当您传递管理器对象时。`this.users = new Users()` 但是代码中的其他地方 `users` 总是会引用一个 `User` 数组。 (3认同)

Aar*_*nLS 5

特定于C#,我发现"框架设计指南:可重用.NET库的约定,惯用法和模式",以获得有关命名逻辑的大量有用信息.

至于找到那些更具体的单词,我经常使用词库并跳过相关单词来尝试找到一个好单词.我尽量不花费很多时间,因为我在开发过程中逐步提出了更好的名称,或者有时意识到SuchAndSuchManager应该真正分解成多个类,然后这个被弃用的类的名称变成一个非问题.