很久以前我读过一篇文章(我相信一篇博客文章),它让我在命名对象的“正确”轨道上:非常谨慎地命名程序中的东西。
例如,如果我的应用程序(作为一个典型的商业应用程序)处理用户,公司和地址,我会有User
,Company
和Address
域类 - 并且可能会出现一个UserManager
,一个CompanyManager
和一个AddressManager
来处理这些事情。
那么你能告诉那些UserManager
,CompanyManager
和AddressManager
做什么吗?不,因为Manager是一个非常通用的术语,适用于您可以对域对象执行的任何操作。
我读过的文章建议使用非常具体的名称。如果它是一个C ++应用程序并且UserManager
的工作正在分配并从堆中释放用户,那么它将不会管理用户,而是保护他们的出生和死亡。嗯,也许我们可以称之为UserShepherd
。
或者UserManager
的工作可能是检查每个User对象的数据并以加密方式对数据进行签名。然后我们有一个UserRecordsClerk
。
现在这个想法一直困扰着我,我尝试应用它。并且非常难以找到这个简单的想法。
我可以描述这些类的功能和(只要我不进入快速和简单的编码)我写的类完全是一个的东西。我想念从名称到名称的是一种名称目录,一种将概念映射到名称的词汇表。
最终,我希望在我的脑海里有类似图案目录的东西(通常设计图案很容易提供对象名称,例如 factory )
Nanny - 帮助对象在创建后达到“可用”状态 - 例如通过连接到其他对象
等等。
那么,你如何处理这个问题呢?你有一个固定的词汇表,你是否动态发明新的名字,或者你认为命名的东西不那么重要或错误?
P.S。:我也对讨论这个问题的文章和博客的链接感兴趣。首先,这是让我思考它的原始文章:Naming Java Classes without a 'Manager'
以下是我在此期间从这个问题中学到的内容的一点摘要。
关于此主题的更多文章/书籍:
我从答案中收集的(主观上!)当前名称前缀/后缀列表:
这条道路的好建议:
不要命名瘫痪。是的,名字非常重要,但它们不足以浪费大量时间。如果你在10分钟内想不出一个好名字,继续前进。
答案 0 :(得分:179)
我问了similar question,但在可能的情况下,我尝试复制.NET框架中已有的名称,并在Java和Android框架中寻找想法。
似乎Helper
,Manager
和Util
是您为协调不包含状态的类而附加的不可避免的名词,通常是程序性和静态的。另一种选择是Coordinator
。
您可以使用这些名称获得特别紫色的内容,并选择Minder
,Overseer
,Supervisor
,Administrator
和Master
之类的内容,但是我说我更喜欢把它当作你习惯的框架名称。
您在.NET框架中找到的一些其他常见后缀(如果这是正确的术语)是:
Builder
Writer
Reader
Handler
Container
答案 1 :(得分:108)
您可以查看source-code-wordle.de,我已经分析了.NET框架和其他一些库的类名最常用的后缀。
前20名是:
答案 2 :(得分:60)
我都是为了好名字,我经常写下在选择名字时要特别小心的重要性。出于同样的原因,在命名事物时我对隐喻持谨慎态度。在最初的问题中,“工厂”和“同步器”看起来就像它们似乎意味着的好名字。然而,“牧羊人”和“保姆”不是,因为它们基于隐喻。代码中的一个类不能字面上一个保姆;你称之为保姆,因为它照顾其他一些非常像现实生活的保姆照顾婴儿或小孩。这在非正式演讲中是可以的,但不是(在我看来)可以在代码中命名类,这些类必须由谁知道谁知道何时维护。
为什么呢?因为隐喻是文化依赖的,并且通常也是个人依赖的。对你来说,命名一个班级“保姆”可以非常清楚,但也许对其他人来说并不是那么清楚。除非您编写的代码仅供个人使用,否则我们不应该依赖它。
在任何情况下,惯例都可以成就或破坏隐喻。 “工厂”本身的使用是基于一个比喻,但它已经存在了很长一段时间,并且目前在编程世界中是众所周知的,所以我认为使用它是安全的。然而,“保姆”和“牧羊人”是不可接受的。
答案 3 :(得分:46)
如果我们正确地模拟现实世界,我们可以不使用任何xxxFactory
,xxxManager
或xxxRepository
类:
Universe.Instance.Galaxies["Milky Way"].SolarSystems["Sol"]
.Planets["Earth"].Inhabitants.OfType<Human>().WorkingFor["Initech, USA"]
.OfType<User>().CreateNew("John Doe");
- )
答案 4 :(得分:35)
这听起来像是一个滑动的斜坡,可以发布在thedailywtf.com上,“ManagerOfPeopleWhoHaveMortgages”等等。
我认为一个单一的Manager类不是好设计是正确的,但使用'Manager'并不错。我们可能会将其分解为UserAccountManager,UserProfileManager,UserSecurityManager等,而不是UserManager。
'经理'是一个好词,因为它清楚地表明一个类不代表一个现实世界的“事物”。 'AccountsClerk' - 我该如何判断这是一个管理用户数据的类,还是代表某个职员的工作人员?
答案 5 :(得分:23)
由于您对这方面的文章感兴趣,您可能对Steve Yegge的观点文章“名词王国中的执行”感兴趣:
http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html
答案 6 :(得分:19)
当我发现自己在考虑在类名中使用Manager
或Helper
时,我认为这是一种代码味道,这意味着我还没有找到正确的抽象和/或我违反了single responsibility principle,所以重构和更多的努力设计往往使命名更容易。
但即使是精心设计的类也不会(总是)自己命名,而您的选择部分取决于您是创建业务模型类还是技术基础结构类。
商业模式类可能很难,因为它们对每个域都不同。我使用了很多术语,例如Policy
用于域内的策略类(例如LateRentalPolicy
),但这些术语通常来自尝试创建“ubiquitous language”,你可以与业务用户共享,设计和命名类,以便他们模拟真实的想法,对象,操作和事件。
技术基础架构类更容易一些,因为它们描述了我们非常熟悉的域。我更喜欢将设计模式名称合并到类名中,例如InsertUserCommand,
CustomerRepository,
或SapAdapter.
我理解关于沟通实现而非意图的关注,但设计模式与类设计的这两个方面相结合 - 至少在您处理基础架构时,您希望实现 design 在您隐藏详细信息时保持透明。
答案 7 :(得分:10)
如果我不能为我的班级提供比XyzManager更具体的名称,那么我将重新考虑这是否真的是一个属于一个类的功能,即建筑“代码味道”。
答案 8 :(得分:9)
使用(例如)GOF book定义的模式,并且在这些模式之后的命名对象在命名类,组织它们和传达意图方面有很长的路要走。大多数人都会理解这种命名法(或至少是其中的一个主要部分)。
答案 9 :(得分:7)
我认为最重要的是要记住:名称是否足够描述?你能看一下这个名字应该做什么吗?在类名中使用“经理”,“服务”或“处理程序”等词语可以被认为过于通用,但由于许多程序员使用它们,因此也有助于理解该类的用途。
我自己一直在使用外观模式(至少,我认为这就是所谓的)。我可以有一个只描述一个用户的User
类,以及一个跟踪我的“用户集合”的Users
类。我没有把班级称为UserManager
因为我不喜欢现实生活中的经理而且我不想被提醒他们:)简单地使用复数形式可以帮助我理解班级的作用。
答案 10 :(得分:5)
特定于C#,我发现"Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries"有很多关于命名逻辑的好信息。
就找到那些更具体的单词而言,我经常使用词库并跳过相关单词来尝试找到一个好单词。我尝试不花费太多时间,因为我在开发过程中提出了更好的名称,或者有时意识到SuchAndSuchManager
应该被分解为多个类,然后是那个已弃用的类的名称变得没有问题。
答案 11 :(得分:2)
我认为这里的关键是在代码的可见性范围内保持一致,即只要每个需要查看/处理代码的人都理解你的命名约定那么即使你决定也应该没问题。称他们为'CompanyThingamabob'和'UserDoohickey'。如果您在公司工作,第一站是查看公司是否有命名约定。如果没有或者您不为公司工作,那么使用对您有意义的术语创建您自己的术语,将其传递给几个随意编码的可信赖的同事/朋友,并纳入任何有意义的反馈。< / p>
应用别人的约定,即使它被广泛接受,如果它没有从你的页面跳出来,那么我的书中有点错误。首先,我需要在不参考其他文档的情况下理解我的代码,但同时它需要足够通用,以至于同一行业中同一领域的其他人都无法理解。
答案 12 :(得分:2)
我会考虑您用于系统的模式,类的命名约定/编目/分组往往由所使用的模式定义。就个人而言,我坚持这些命名约定,因为它们是最有可能让另一个人能够拿起我的代码并运行它。
例如,UserRecordsClerk可能更好地解释为扩展UserRecordsClerk和CompanyRecordsClerk实现然后专注的通用RecordsClerk接口,这意味着可以查看接口中的方法以查看其子类通常用于什么。< / p>
有关信息,请参阅Design Patterns这样的书,它是一本很好的书,可以帮助您清理您的目标 - 如果您还没有使用它! ; o)
我认为只要您的模式选择得恰到好处并尽可能使用,那么非常简单的直接类名就足够了!