关于设计模式:命名类-如何避免将所有内容都称为whatever manager?

Naming Classes - How to avoid calling everything a “<WhatEver>Manager”?

很久以前,我读过一篇文章(我相信是一篇博客文章),这篇文章让我对命名对象有了正确的认识:对程序中的命名要非常谨慎。

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

那么,你能说出那些UserManagerCompanyManagerAddressManager是做什么的吗?不,因为管理器是一个非常通用的术语,适用于您可以对域对象执行的任何操作。

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

或者,UserManager的工作可能是检查每个用户对象的数据,并对数据进行加密签名。那么我们就有一个UserRecordsClerk

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

我可以描述类是做什么的(只要我不陷入快速和肮脏的编码中),我写的类只做一件事。我想从描述到名字是一种名字目录,一种将概念映射到名字的词汇表。

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

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

那么,你如何处理这个问题?你有固定的词汇量吗,你是在不断地发明新的名字,还是你认为给那些不那么重要或错误的东西命名?

附言:我对讨论这个问题的文章和博客的链接也很感兴趣。首先,这里有一篇让我思考的原创文章:在没有"管理者"的情况下命名Java类

更新:答案摘要

下面是我从这个问题中学到的一些小结。

  • 不要创造新的隐喻(保姆)
  • 看看其他框架的作用

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

  • 你发现自己经常在课前/课后写些什么名字?
  • 命名类的最佳方法是什么?
  • 书:设计模式:可重用面向对象软件的元素(精装本)
  • 书:企业应用架构模式(精装本)
  • 书:实现模式(平装本)

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

  • 协调员
  • 建设者
  • 作家
  • 读者
  • 处理程序
  • 集装箱
  • 协议
  • 靶标
  • 转换器
  • 控制器
  • 视图
  • 工厂
  • 实体
  • 铲斗

还有一个很好的建议:

Don't get naming paralysis. Yes, names are very important but they're not important enough to waste huge amounts of time on. If you can't think up a good name in 10 minutes, move on.


我问了一个类似的问题,但是在可能的情况下,我尝试复制.NETFramework中的名字,我在Java和Android框架中寻找一些想法。

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

你可以用这些名字得到特别紫色的prosey,然后去买像MinderOverseerSupervisorAdministratorMaster这样的东西,但正如我说的,我更喜欢保持你习惯的框架名称。

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

  • Builder
  • Writer
  • Reader
  • Handler
  • Container


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

前20名是:

  • 属性
  • 类型
  • 帮手
  • 收集
  • 转换器
  • 处理程序
  • 信息
  • 供应商
  • 例外
  • 服务
  • 要素
  • 经理
  • 结点
  • 选项
  • 工厂
  • 语境
  • 项目
  • 设计师
  • 基础
  • 编辑


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

为什么?因为隐喻依赖于文化,而且往往也依赖于个人。对你来说,给一个班命名为"保姆"是非常清楚的,但对其他人来说,这可能并不那么清楚。我们不应该依赖它,除非你写的代码只是为了个人使用。

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


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

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

;-)


在dailywtf.com、managerofpeoplewhohavedmortgages等网站上发布的内容听起来像是一个滑坡。

我认为一个单片管理器类不是好的设计是正确的,但是使用"管理器"也不错。我们可以将其分解为useraccountmanager、userprofilemanager、usersecuritymanager等,而不是usermanager。

"manager"是一个很好的词,因为它清楚地表明一个类并不代表一个真实的"事物"。accountstrick'-我该如何判断这是一个管理用户数据的类,还是代表一个为他们的工作做会计职员的人?


既然你对这方面的文章感兴趣,你可能会对Steve Yegge的观点文章"名词王国的执行"感兴趣:

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


当我想到在类名中使用ManagerHelper时,我认为它是一种代码味道,这意味着我还没有找到正确的抽象和/或我违反了单一责任原则,因此重构和在设计中投入更多的精力通常会使命名更加容易。

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

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

技术基础设施类要简单一些,因为它们描述了我们非常熟悉的领域。我更喜欢将设计模式名称合并到类名中,比如InsertUserCommand,CustomerRepository,SapAdapter.,我理解关于通信实现而不是意图的关注,但是设计模式结合了类设计的这两个方面-至少当您处理需要实现设计的基础设施时即使在隐藏细节的时候也是透明的。


如果我不能给我的类取一个比XYZManager更具体的名称,这将是我重新考虑这是否真的是一个类中共同拥有的功能,即架构"代码味道"的一点。


熟悉gof书中定义的模式,在这些模式之后命名对象,在命名类、组织类和传达意图方面给我带来了很大的帮助。大多数人都会理解这个术语(或者至少是其中的一个主要部分)。


我认为最重要的是:这个名字足够描述性吗?你能看一下这个班级的名字吗?在类名中使用诸如"manager"、"service"或"handler"之类的词可能被认为太通用了,但是由于许多程序员使用这些词,它也有助于理解类的用途。

我自己也经常使用立面图案(至少,我认为这就是所谓的)。我可以有一个只描述一个用户的User类和一个跟踪"用户集合"的Users类。我不称A类为UserManager,因为我不喜欢现实生活中的管理者,也不想被提醒:)简单地使用复数形式有助于我理解这个类的作用。


针对C,我发现"框架设计指南:可重用.NET库的惯例、习惯用法和模式"对命名逻辑有很多很好的信息。

至于找到那些更具体的词,我经常使用同义词库,并跳过相关的词,试图找到一个好的。不过,我尽量不花太多时间使用它,随着开发的进展,我会想出更好的名称,或者有时会意识到SuchAndSuchManager实际上应该划分为多个类,然后该不推荐的类的名称就变成了一个问题。


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

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

看一本像《设计模式》这样的书来获取信息,它是一本很好的书,如果你还没有使用它的话,它可能会帮助你明确你的代码目标。o)

我认为只要你的模式被恰当地选择和使用,那么相当不具创造性的直接类名就足够了!


我相信这里的关键是在代码的可见性范围内保持一致,即只要需要查看/处理代码的每个人都了解您的命名约定,那么这就没问题了,即使您决定将他们称为"Companythingamabob"和"UserDooHickey"。如果你在一家公司工作,第一站是看是否有公司命名惯例。如果没有或者你没有为一家公司工作,那么就用对你有意义的术语来创建你自己的公司,把它传给几个值得信赖的同事/朋友,这些同事/朋友至少是随便编代码的,并加入任何有意义的反馈。

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