ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java类设计规约

2020-02-24 21:51:53  阅读:522  来源: 互联网

标签:Java 规约 equals Rule should Sonar 设计 方法 属性


原文:https://vipshop.github.io/vjtools/#/standard/chapter05

Rule 1. 【推荐】类成员与方法的可见性最小化

任何类、方法、参数、变量,严控访问范围。过于宽泛的访问范围,不利于模块解耦。思考:如果是一个private的方法,想删除就删除,可是一个public的service方法,或者一个public的成员变量,删除一下,不得手心冒点汗吗?

例外:为了单元测试,有时也可能将访问范围扩大,此时需要加上JavaDoc说明或vjkit中的@VisibleForTesting注解。


Rule 2.【推荐】 减少类之间的依赖

比如如果A类只依赖B类的某个属性,在构造函数和方法参数中,只传入该属性。让阅读者知道,A类只依赖了B类的这个属性,而不依赖其他属性,也不会调用B类的任何方法。

a.foo(b);     //WRONG

a.foo(b.bar); //RIGHT

Rule 3.【推荐】 定义变量与方法参数时,尽量使用接口而不是具体类

使用接口可以保持一定的灵活性,也能向读者更清晰的表达你的需求:变量和参数只是要求有一个Map,而不是特定要求一个HashMap。

例外:如果变量和参数要求某种特殊类型的特性,则需要清晰定义该参数类型,同样是为了向读者表达你的需求。


Rule 4. 【推荐】类的长度度量

类尽量不要超过300行,或其他团队共同商定的行数。

对过大的类进行分拆时,可考虑其内聚性,即类的属性与类的方法的关联程度,如果有些属性没有被大部分的方法使用,其内聚性是低的。


Rule 5.【推荐】 构造函数如果有很多参数,且有多种参数组合时,建议使用Builder模式

Executor executor = new ThreadPoolBuilder().coreThread(10).queueLenth(100).build();

即使仍然使用构造函数,也建议使用chain constructor模式,逐层加入默认值传递调用,仅在参数最多的构造函数里实现构造逻辑。

public A(){
  A(DEFAULT_TIMEOUT);
}

public A(int timeout) {
  ...
}

Rule 6.【推荐】构造函数要简单,尤其是存在继承关系的时候

可以将复杂逻辑,尤其是业务逻辑,抽取到独立函数,如init(),start(),让使用者显式调用。

Foo foo = new Foo();
foo.init();

Rule 7.【强制】所有的子类覆写方法,必须加@Override注解

比如有时候子类的覆写方法的拼写有误,或方法签名有误,导致没能真正覆写,加@Override可以准确判断是否覆写成功。

而且,如果在父类中对方法签名进行了修改,子类会马上编译报错。

另外,也能提醒阅读者这是个覆写方法。

最后,建议在IDE的Save Action中配置自动添加@Override注解,如果无意间错误同名覆写了父类方法也能被发现。

  • Sonar-1161: "@Override" should be used on overriding and implementing methods


Rule 8.【强制】静态方法不能被子类覆写。

因为它只会根据表面类型来决定调用的方法。

Base base = new Children();

// 下句实际调用的是父类的静态方法,虽然对象实例是子类的。
base.staticMethod();

Rule 9.静态方法访问的原则

9.1【推荐】避免通过一个类的对象引用访问此类的静态变量或静态方法,直接用类名来访问即可

目的是向读者更清晰传达调用的是静态方法。可在IDE的Save Action中配置自动转换。

int i = objectA.staticMethod(); // WRONG

int i = ClassA.staticMethod(); // RIGHT
  • Sonar-2209: "static" members should be accessed statically

  • Sonar-2440: Classes with only "static" methods should not be instantiated

9.2 【推荐】除测试用例,不要static import 静态方法

静态导入后忽略掉的类名,给阅读者造成障碍。

例外:测试环境中的assert语句,大家都太熟悉了。

  • Sonar-3030: Classes should not have too many "static" imports 但IDEA经常自动转换static import,所以暂不作为规则。

9.3【推荐】尽量避免在非静态方法中修改静态成员变量的值

// WRONG
public void foo() {
  ClassA.staticFiled = 1;
}
  • Sonar-2696: Instance methods should not write to "static" fields

  • Sonar-3010: Static fields should not be updated in constructors


Rule 10.【推荐】 内部类的定义原则

当一个类与另一个类关联非常紧密,处于从属的关系,特别是只有该类会访问它时,可定义成私有内部类以提高封装性。

另外,内部类也常用作回调函数类,在JDK8下建议写成Lambda。

内部类分匿名内部类,内部类,静态内部类三种。

1) 匿名内部类 与 内部类,按需使用:

在性能上没有区别;当内部类会被多个地方调用,或匿名内部类的长度太长,已影响对调用它的方法的阅读时,定义有名字的内部类。

2) 静态内部类 与 内部类,优先使用静态内部类:

  1. 非静态内部类持有外部类的引用,能访问外类的实例方法与属性。构造时多传入一个引用对性能没有太大影响,更关键的是向阅读者传递自己的意图,内部类会否访问外部类。

  2. 非静态内部类里不能定义static的属性与方法。

  • Sonar-2694: Inner classes which do not reference their owning classes should be "static"

  • Sonar-1604: Anonymous inner classes containing only one method should become lambdas


Rule 11.【推荐】使用getter/setter方法,还是直接public成员变量的原则。

除非因为特殊原因方法内联失败,否则使用getter方法与直接访问成员变量的性能是一样的。

使用getter/setter,好处是可以进一步的处理:

  1. 通过隐藏setter方法使得成员变量只读

  2. 增加简单的校验逻辑

  3. 增加简单的值处理,值类型转换等

建议通过IDE生成getter/setter。

但getter/seter中不应有复杂的业务处理,建议另外封装函数,并且不要以getXX/setXX命名。

如果是内部类,以及无逻辑的POJO/VO类,使用getter/setter除了让一些纯OO论者感觉舒服,没有任何的好处,建议直接使用public成员变量。

例外:有些序列化框架只能从getter/setter反射,不能直接反射public成员变量。


Rule 12.【强制】POJO类必须覆写toString方法。

便于记录日志,排查问题时调用POJO的toString方法打印其属性值。否则默认的Object.toString()只打印类名@数字的无效信息。


Rule 13. hashCode和equals方法的处理,遵循如下规则:

13.1【强制】只要重写equals,就必须重写hashCode。而且选取相同的属性进行运算。

13.2【推荐】只选取真正能决定对象是否一致的属性,而不是所有属性,可以改善性能。

13.3【推荐】对不可变对象,可以缓存hashCode值改善性能(比如String就是例子)。

13.4【强制】类的属性增加时,及时重新生成toString,hashCode和equals方法。

  • Sonar-1206: "equals(Object obj)" and "hashCode()" should be overridden in pairs


Rule 14.【强制】使用IDE生成toString,hashCode和equals方法。

使用IDE生成而不是手写,能保证toString有统一的格式,equals和hashCode则避免不正确的Null值处理。

子类生成toString() 时,还需要勾选父类的属性。


Rule 15. 【强制】Object的equals方法容易抛空指针异常,应使用常量或确定非空的对象来调用equals

推荐使用java.util.Objects#equals(JDK7引入的工具类)

"test".equals(object);  //RIGHT

Objects.equals(object, "test"); //RIGHT
  • Sonar-1132: Strings literals should be placed on the left side when checking for equality


Rule 16.【强制】除了保持兼容性的情况,总是移除无用属性、方法与参数

特别是private的属性、方法、内部类,private方法上的参数,一旦无用立刻移除。信任代码版本管理系统。

  • Sonar-3985: Unused "private" classes should be removed

  • Sonar-1068: Unused "private" fields should be removed

  • Sonar: Unused "private" methods should be removed

  • Sonar-1481: Unused local variables should be removed

  • Sonar-1172: Unused method parameters should be removed Sonar-VJ版只对private方法的无用参数告警。


Rule 17.【推荐】final关键字与性能无关,仅用于下列不可修改的场景

1) 定义类及方法时,类不可继承,方法不可覆写;

2) 定义基本类型的函数参数和变量,不可重新赋值;

3) 定义对象型的函数参数和变量,仅表示变量所指向的对象不可修改,而对象自身的属性是可以修改的。


Rule 18.【推荐】得墨忒耳法则,不要和陌生人说话

以下调用,一是导致了对A对象的内部结构(B,C)的紧耦合,二是连串的调用很容易产生NPE,因此链式调用尽量不要过长。

obj.getA().getB().getC().hello();
微信公众号

 ​ 

标签:Java,规约,equals,Rule,should,Sonar,设计,方法,属性
来源: https://www.cnblogs.com/niugang0920/p/12359050.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有