编程中最难的就是命名?这几招教你快速上手
你可不能像给狗狗取名字那样给类、方法、变量命名。仅仅因为它很可爱或者听上去不错。
在写代码的时候,你要经常想着,那个最终维护你代码的人可能将是一个有暴力倾向的疯子,并且他还知道你住在哪里。
为什么命名很重要?
Aliware
在项目中,从项目的创建到方法的实现,每一步都以命名为起点,我们需要给变量、方法、参数、类命名,这些名字出现在代码的每个角落,随处可见,混乱或错误的命名不仅让我们对代码难以理解,更糟糕的是,会误导我们的思维,导致对代码的理解完全错误。如果整个项目始终贯穿着好的命名,就能给阅读者一个神清气爽的开始,也能给阅读者一个好的指引。
为什么很难正确命名?
Aliware
有人称编程中最难的事情就是命名。我同样深以为然,中国有句古话叫做万事开头难。抛开环境搭建,真正到了编码阶段第一件事就是命名,而最常见的一种情况,就是毫无目的、仅凭个人的喜好的去决定了一个名字。但因为没有想清楚目标和具体实施步骤,所以进行过程中往往会面临无数次的小重构甚至是推倒重来。
1、缺乏意愿
2、缺乏思考
3、缺乏技巧
如何正确的命名?
Aliware
这里不讨论具体语言的命名规则,原因是不同编程语言命名规则各不相同,甚至不同团队间相同语言的命名规则也有出入。这里主要从提高可读性出发,结合我所在的客户端团队日常开发情况,以Java作为演示语言,给一些关于命名的建议。
1、名副其实
Case1:到底怎样算End?
代码示例:
public interface OnRequestListener {
/**
* 请求结束 只有成功点才认为是真正的结束
* @param ...
*/
void onRequestEnd(....);
/**
* 请求开始
* @param ...
*/
void onRequestStart(...);
}
// 省略注释
public interface OnRequestListener {
void onStart(....);
void onSuccess(....);
void onFailure(...);
}
2、避免误导
在每种语言中都有内置的标识符,他们都有特定的含义,如果和他们没有关联就不要在命名中加上他们。
2.1 避免使用令人误解的名字
Case1:命错名的集合
代码示例:
private List<SectionModel> dataSet;
大脑活动:
private List<SectionModel> dataList;
或者
private List<SectionModel> sections;
Case2:不是View的View类
代码示例:
/** 作者+日期 */
public class RItemOverlayView {
}
/** 作者+日期 */
public class NRItemOverlayView {
}
大脑活动:
// 放在首页推荐场景的包下
public class ItemOverlayViewCreator {
}
// 放在购后推荐场景的包下
public class ItemOverlayViewCreator {
}
Case3:整形变量为啥要用is开头
代码示例:
private int isFirstEnter = 0;
大脑活动:
private boolean isFirstEnter = true;
Case4:开关作用反掉啦
代码示例:
....
if (InfoFlowOrangeConfig.getBooleanValue(POST_DELAYED_HIDE_COVER_VIEW_ENABLE, true)) {
hideCoverImageView();
} else {
delayedHideCoverImageView();
}
大脑活动:
....
if (InfoFlowOrangeConfig.getBooleanValue(IMMEDIATELY_HIDE_COVER_VIEW_ENABLE, true)) {
hideCoverImageView();
} else {
delayedHideCoverImageView();
}
3、做有意义的区分
3.1 避免在名字中使用数字
case1: 来自包名的暴击
问题示例:
recommend:推荐的公共工具和模块; recommend2:收藏夹场景的推荐实现; recommend3:首页场景的推荐实现; recommend4:购后场景的推荐实现;
3.2 避免使用具有相似含义的名字
case1:同一个类下的“刷新7剑客”
case2:4个数据源定义,该用谁呢
public interface IR4UDataSource {
....
}
声明2:
public interface RecommendIDataSource {
....
}
声明3:
public interface IRecommendDataResource {
....
}
声明4:
public class RecmdDataSource {
....
}
大脑活动:
3.3 避免使用具有不同含义但却有相似名字的变量
case1 : 大家都是view,到底谁是谁
public void showOverlay(@NonNull View view ...) {
...
View rootView = getRootView(view);
DxOverlayViewWidget dView = createDxOverlayViewWidget();
dView.showOverLayer(view.getContext(), (ViewGroup)rootView, cardData, itemData);
...
}
public void showOverlay(@NonNull View hostView ...) {
...
ViewGroup parentView = getParentView(hostView);
DxOverlayViewWidget dxOverlayViewWidget = createDxOverlayViewWidget();
dxOverlayViewWidget.showOverLayer(hostView.getContext(), parentView, ...);
...
}
4.使用读的出来的名称
4.1 避免使用令人费解的缩写
Case1:接口定义中的俏皮缩写
/**
* Created by *** on 16/8/6.
*/
public interface IR4UDataSource {
....
}
大脑活动:
public interface IRecommendForYouDataSource {
....
}
Case2:成员变量命名的缩写
....
// 标题指示器(indicators)
private LinearLayout mTabLL;
private TabLayout mTabLayout;
....
....
private LinearLayout mTabLayoutParentView;
private TabLayout mTabLayout;
....
Case3:局部变量命名的缩写
....
for (PageParams.GroupBuckets ss:params.groupBucketIds.values()) {
if (ss != null) {
bucketIds.removeAll(ss.bucketIdsAll);
Collections.addAll(bucketIds, ss.currentBucketIds);
}
}
....
大脑活动:
for (PageParams.GroupBuckets groupBuckets :params.groupBucketIds.values()) {
if (groupBuckets != null) {
....
}
}
5、使用可搜索的名称
5.1 给魔法值赐名
Case1:数字魔法值没法搜索也看不懂
public static void updateImmersiveStatusBar(Context context) {
....
if (TextUtils.equals(isFestivalOn, "1")) {
if (TextUtils.equals(navStyle, "0") || TextUtils.equals(navStyle, "1")) {
....
} else if (TextUtils.equals(navStyle, "2")) {
....
}
}
....
}
大脑活动:
public static final String FESTIVAL_ON = "1";
public static final String NAV_STYLE_FESTIVAL = "0";
public static final String NAV_STYLE_SKIN = "1";
public static final String NAV_STYLE_DARK = "2";
public static void updateImmersiveStatusBar(Context context) {
....
if (TextUtils.equals(isFestivalOn, FESTIVAL_ON)) {
if (TextUtils.equals(navStyle, NAV_STYLE_FESTIVAL)
|| TextUtils.equals(navStyle, NAV_STYLE_SKIN)) {
....
} else if (TextUtils.equals(navStyle, NAV_STYLE_DARK)) {
....
}
}
....
}
5.2 避免在名字中拼错单词
Case1:接口拼错单词,实现类也被迫保持队形
代码示例:
public interface xxx {
....
void destory();
}
public interface xxx {
....
void destroy();
}
6、类的命名
7、方法的命名
7.1 避免对方法使用无意义或者模棱两可的动词
Case1: 名不副实的process
/**
* 处理主图的数据
*
* @return 如果有浮层数据就返回true,没有就返回false
*/
private boolean processMainPic() {
....
boolean hasMainPicFloat = false;
....
return hasMainPicFloat;
}
// 调用处
boolean hasMainPicFloat = processMainPic();
/**
* 是否有浮层数据
*
* @return 如果有浮层数据就返回true,没有就返回false
*/
private boolean hasFloatData($MainPictureData) {
....
boolean hasFloatData = false;
....
return hasFloatData;
}
// 调用处
boolean hasFloatData = hasFloatData(mainPictureData);
Case2: 我该如何正确使用这个方法
// 10多处调用
... = GatewayUtils.processTime(System.currentTimeMillis());
public class GatewayUtils {
....
// 这个方法没有注释
public static long processTime(long time) {
return time + (SDKUtils.getTimeOffset() * 1000L);
}
....
}
public static long currentNetworkTime() {
return System.currentTimeMillis() + (SDKUtils.getTimeOffset() * 1000L);
}
7.2 避免返回和方法名定义不一致的类型
Case1: 私有方法就可以乱定义吗?
// 唯一调用处
final IPageProvider pageProvider = checkActivityAvaliable();
if (pageProvider == null) {
....
return;
}
// 函数声明
private IPageProvider checkActivityAvaliable() {
IPageProvider pageProvider = pageProviderWeakReference.get();
if (pageProvider == null) {
PopFactory.destroyPopCenter(pageName);
return null;
}
return pageProvider;
}
大脑活动:
final IPageProvider pageProvider = pageProviderWeakReference.get();
if (pageProvider == null) {
PopFactory.destroyPopCenter(pageName);
....
return;
}
Aliware
1.对自己严格自律,自己写代码时要有一种希望把每个名称都命名好的强烈意识和严格的自律意识;