编程5分钟,起名2小时。
方法应该具有单一职责特效,通过一个比较好的命名来实现较高的可读性。即实现less is more。那么平时在开发中如何对一些常见的方法来进行命名?
方法命名采用小驼峰的形式,首字小写,往后的每个单词首字母都要大写。和类名不同的是,方法命名一般为动词或动词短语,与参数或参数名共同组成动宾短语,即动词 + 名词。一个好的函数名一般能通过名字直接获知该函数实现什么样的功能。
举几个常见的例子:
下面可以看到一个“名不符实”的危害。
函数取名最忌讳的是"名不副实",举个例子,假如有个Cache类,里面有个函数判断key是否过期:
public boolean isExpired(String key) {
// 当前时间戳
long curTimestamp = DateUtils.nowUnixTime();
// 获取key的存入时间戳
long storeTimestamp = getStoreTimestamp(key);
if (curTimestamp - storeTimestamp > MAX_EXPIRE_SECONDS) {
// 注意这个地方的delete是个隐藏逻辑
delete(key);
return true;
}
return false;
}
上面这个函数从函数字面意思看是判断key是否过期,但是!!它居然在函数里面隐藏了一段特殊逻辑:如果过期则删除掉key。这个就是典型的"名不副实",这个是最忌讳的,会给后续的开发人员留下"巨坑"。
有两种方式去优化这段代码:
方式一:将隐藏逻辑去掉
public boolean isExpired(String key) {
// 当前时间戳
long curTimestamp = DateUtils.nowUnixTime();
// 获取key的存入时间戳
long storeTimestamp = getStoreTimestamp(key);
if (curTimestamp - storeTimestamp > MAX_EXPIRE_SECONDS) {
return true;
}
return false;
}
方式二:改变函数名字
public int deleteIfExpired(String key) {
// 当前时间戳
long curTimestamp = DateUtils.nowUnixTime();
// 获取key的存入时间戳
long storeTimestamp = getStoreTimestamp(key);
if (curTimestamp - storeTimestamp > MAX_EXPIRE_SECONDS) {
return delete(key);
}
return 0;
}
举例说明:
场景:小明可以将一份练习分享给小红,可以多次分享,但非首次分享的场景下直接返回分享成功。
方法命名:
find方法给人的感觉是查找数据,找到则返回,找不到则返回null,这里返回boolean很不友好。且有些面向过程的感觉,不知道这方法的目的是什么。
exists方法是否存在,返回boolean值合适,但是命名偏面向过程的感觉,不知道这方法的目的是什么。
is:是否存在,shared:是否被分享过。这就能准确的表述出该方法的目的(即产品需求)。但是缺点是:这个方法中有逻辑会填充result列表,但是命名中并未体现出。
(推荐)4. List<Result> getResultsIfShared(String sign,String targetUserId);
若照片被分享过,那么转化为Results对象输出,这个命名便可以体现出这个方法的目的和实际做的工作。
(思考)5. int addResultsIfShared(String sign,String targetUserId,List<Result> results)
前提:
[1] List<Result>作为入参,通过引用传递来修改内部值,以达到传递最终结果的目的;
[2] 需要boolean值的结果,来告诉main方法,该照片是否被分享过;
若照片被分享过,那么填充Results对象,填充成功返回1,填充失败返回0;
pre- prefix前缀,suf- suffix后缀,alo-alone 单独使用
若方法返回boolean类型,可以推荐使用如下的格式。
| 位置 | 单词 | 意义 | 例子 |
|---|---|---|---|
| pre | is | 对象是否符合期待的状态 | isValid |
| pre | can | 对象能否执行所期待的动作 | canRemove |
| pre | should | 调用方执行某个命令 或方法是好还是不好应不应该,或者说推荐还是不推荐 | shouldMigrate |
| pre | has | 对象/集合是否持有所期待的数据和属性 | hasObservers |
| pre | exists | 对象/集合是否存在所期待的数据和属性 | existsObservers |
| pre | contains | 判断集合是否保存某个元素 | containsBeanDefinition |
| pre | needs | 调用方是否需要执行某个命令或方法 | needsMigrate |
| 位置 | 单词 | 意义 | 例子 |
|---|---|---|---|
| pre | ensure | 检查是否为期待的状态 不是则抛出异常或返回error code | ensureCapacity |
| pre | validate/check | 检查是否为正确的状态 不是则抛出异常或返回error code | validateInputs |
| 位置 | 单词 | 意义 | 例子 |
|---|---|---|---|
| suf | YyyIfXxx | 如果发生了Xxx,则执行Yyy | |
| suf | IfNeed | 需要的时候执行,不需要则什么都不做 | drawIfNeed |
| pre | might | 同上 | mightCreate |
| pre | try | 尝试执行 失败时抛出异常 或是返回errorcode | tryCreate |
| suf | OrDefault | 尝试执行 失败时返回默认值 | getOrDefault |
| suf | OrElse | 尝试执行 失败时返回 实际参数中指定的值 | getOrElse |
| pre | force | 强制尝试执行 error抛出异常或是返回值 | forceCreate, forceStop |
| 位置 | 单词 | 意义 | 例子 | 使用程度 |
|---|---|---|---|---|
| pre | make | 借助多个对象来创建对象 | makeAccountWithUserAndDept | |
| pre | create/new | 新创建 | newAccount | 高 |
| pre | from | 从既有的某物新建 或是从其他的数据新建 | fromConfig | 高 |
| pre | to | 转换 | toString | 高 |
| pre | transformed | 转换 | transformedBeanName | 高 |
| pre | save/store | 保存 | saveAccount | |
| pre | delete/remove | 删除 | deleteAccount | |
| pre | clear/reset | 清除或恢复到初始状态 | clearAll | |
| pre | update | 更新 | updateAccount |
| 位置 | 单词 | 意义 | 例子 | 使用程度 |
|---|---|---|---|---|
| pre | get | 得到 | getAccount | 高 |
| pre | find/lookup | 找到 | 高 | |
| pre | resolve | 解析得到(偏复杂逻辑) | 高 | |
| pre | compute | 计算得到(耗CPU) | 高 | |
| pre | load | 本地磁盘读取 | 高 | |
| pre | fetch | 网络读取 | 高 | |
| suf | IfAbsent | 存在时缓存读取缓存,否则去“获取” | fetchAccountIfAbsenet | 高 |
| suf | FromCache | 只读取缓存读取 | 高 |
| 单词 | 意义 |
|---|---|
| resolve 解析/compute 计算 | get、find找到 |
| find 查找 | lookup 搜索 |
| split分割 | merge合并/combine 使...结合 |
| inject注入 | extract提取 |
| increase 增加 | decrease 减少 |
| encode 编码 | decode 解码 |
| encrypt 加密 | decrypt 解密 |
| encode 编码 | decode 解码 |
| parse 解析 | emit 生成 |
| bind 绑定 | separate 分离 |
| backup 备份 | restore 恢复 |
| reorderXxxToEnd 将Xxx重排序填充到最后 |
| 单词 | 意义 | 举例 | 说明 |
|---|---|---|---|
| from | 从...创建 | Xxx fromConfig() | 从Config对象中创建Xxx对象 |
| to | 转化 | toString(Xxx x) | 将入参Xxx转化为String对象 |
| of | 从...中获取 | pathOf(Xxx xxx) | 从Xxx中获取path路径 |
| with | 和 | writeWithMessageConverters | 使用MessageConverters进行写操作 |
| by | 通过 | getStudentById | 通过id获取Student对象 |
| in | 在...in | isBeanNameInUse | 确定给定的bean名称是否(已在此工厂中)使用 |
| for | 为了 | getMappingForMethod | 对于Method对象,来获取Mapping对象 |
| within | 在...内 | getPathWithinApplication | 在应用内获取路径 |
| as | 作为 | getValuesAsList | 将...转成List |
将Spring源码中找到一些使用介词的方法。
getMappingForMethod:在Method中获取Mapping对象;
getObjectForBeanInstance:在BeanInstance中获取Object对象;
getCachedObjectForFactoryBean:在FactoryBean中获取CachedObject;
isBeanEligibleForMetadataCaching:BeanEligible是否在MetadataCaching中;
getTypeForFactoryBean:在FactoryBean获取Type;
getLookupPathForRequest:对于Request对象,获取LookupPath属性;
getObjectFromFactoryBean:从给定的FactoryBean获取要公开的对象。
setContentDispositionFormData:从Data对象来设置ContentDisposition对象。
isBeanNameInUse:确定给定的bean名称是否(已在此工厂中)使用,
isPrototypeCurrentlyInCreation:返回指定的原型bean当前是否正在创建中
writeWithMessageConverters:使用MessageConverters进行写操作
requestedType.isCompatibleWith(producibleType):【参数作为定语】requestedType是否和producibleType是可共用的。
HttpRange.toResourceRegions(httpRanges, resource); 静态方法:HttpRange转化为ResourceRegions对象。
reorderXmlConvertersToEnd(converters):将Xml格式转化器重排序放到最后;
getPathWithinServletMapping:在ServletMapping内,获取path路径;
个人总结:方法模板
一个好的思路是:可以写一些英文注释,然后在这些英文注释中提取方法名。
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2
我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)