整洁代码
以业务为导向命名[operateMaxSaleQtyLogs] > 以技术命名[operateMaxSaleQtyLogList] > 随意命名 [logList]
Rule 1. 【推荐】变量名称最好:名词、短语、形容词
Rule 2. 【推荐】不要在变量中包含多余的信息
badCase:User userWithNameAndAge = newUser()
Rule 3. 【推荐】避免误导
生成的单号,不要使用数字0、1和字母o、O、l、L
Rule 4. 【推荐】做有意义的区分:避免废话
product和productData、productInfo意思无区别
customer和customerData没区别
name和nameStr没区别
Rule 1. 【推荐】函数名称动词 + 名词
Rule 2. 【推荐】函数长度
最好能20行以内
造成长函数的原因:
Rule 3. 【推荐】只做一件事
每个函数一个抽象层级(锁库-较高抽象、查询算法或查档期-中间抽象、最大售卖量转换为字符串-低抽象)
反例:一个方法里,前20行代码在进行很复杂的基本价格计算,然后调用一个折扣计算函数,再调用一个赠品计算函数。
此时可将前20行也封装成一个价格计算函数,使整个方法在同一抽象层级上。
Rule 4. 【推荐】向下规则
每个函数后面,都紧跟着位于下一抽象层级的函数
public void test(){
//xxx
a();
//yyy
}
private void a() {
//
b();
//
}
private void b() {
//
}
Rule 5. 【推荐】参数个数尽量小于3个
1)如果多个参数同属于一个对象,直接传递对象。
例外: 你不希望依赖整个对象,传播了类之间的依赖性。
2)将多个参数合并为一个新创建的逻辑对象。
例外: 多个参数之间毫无逻辑关联。
3)将函数拆分成多个函数,让每个函数所需的参数减少。
Rule 6. 【推荐】减少记忆参数顺序的负担
AssertEquals(expected,actual)==》 assertExpectedEqualsActual(expected,actual)
Rule 7. 【推荐】尽量减少重复的代码,抽取方法
超过5行以上重复的代码,都可以考虑抽取公用的方法。
Rule 8.【推荐】需要进行参数校验
执行时间开销很大的方法。此情形中,参数校验时间几乎可以忽略不计,但如果因为参数错误导致中间执行回退,或者错误,代价更大。
class A {
void hello(List list);
void hello(ArrayList arrayList);
}
List arrayList = new ArrayList();
a.hello(arrayList);//调用的是hello(List list),因为arrayList的定义类型是List
Rule 9.【推荐】不要返回null
如果你打算在方法中返回null,不如抛出异常,或者返回特例对象(Collections。emptylist()等)
Rule 10.【推荐】入参不要传递null
入参为null,也很容易npe
大部分人阅读代码的习惯是,先看此方法整体1、2、3做什么,然后再看1中具体细节
public void invest(long userId, long financialProductId) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.DATE, (calendar.get(Calendar.DATE) + 1));
if (calendar.get(Calendar.DAY_OF_MONTH) == 1) {
return;
}
//...
}
public void invest(long userId, long financialProductId) {
if (isLastDayOfMonth(new Date())) { //先整体再细节
return;
}
//...
}
public boolean isLastDayOfMonth(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.DATE, (calendar.get(Calendar.DATE) + 1));
if (calendar.get(Calendar.DAY_OF_MONTH) == 1) {
return true;
}
return false;
}
Rule 1. 【推荐】命名使用名词、名词短语叠
避免使用动词(Manager、Processor)
Rule 2. 【推荐】字段未分组避免大类的产生、
可以将一个大类n多个字段,按照商品基本信息、档期信息、库存信息、其它信息等几个模块分组。
Rule 3. 【推荐】高内聚
类应该只有少数实体变量、类中方法操作的变量越多,类就越内聚。
大函数 -> 小函数(使用了大函数的4个变量)-> 将4个变量提升为类的实体变量 -> 丧失内聚(新增了4个只是为了少量函数而存在的实体变量)
-> 将这些想要共享某些实体变量的函数 和 实体,抽离为一个新的小类,这样就完成了大函数 到 小函数的拆分,同时类也符合高内聚
Rule 1. 【推荐】加减空格,乘除不加空格
int result = temp - 2*a*b ;
Rule 1. 【推荐】少用if-else方式,多用哨兵语句式以减少嵌套层次
if (condition) {
...
return obj;
}
// 接着写else的业务逻辑代码;
Rule 2.【推荐】减少使用取反的逻辑
不使用取反的逻辑,有利于快速理解。且大部分情况,取反逻辑存在对应的正向逻辑写法。
Rule 3.【推荐】能用while循环实现的代码,就不用do-while循环
Rule 1.【推荐】面向对象编程
eg1: 计算图形的面积
面向对象编程
// 正方形
@Data
public class Square {
private Double side;
}
// 圆形
@Data
public class Circle {
private Double r;
}
// 计算类
public class Calculate {
public double area(Object shape) {
if (shape instanceof Square) {
Square square = (Square) shape;
Double side = square.getSide();
return side * side;
}
if (shape instanceof Circle) {
Circle circle = (Circle) shape;
Double r = circle.getR();
return Math.PI * r * r;
}
throw new NoSuchElementException();
}
}
当新增三角形这种数据结构时,需要:添加三角形类、需要在计算类中新增if判断条件,违背了开闭原则
面向对象编程
// 接口定义方法:计算面积
public interface Shape {
/**
* 计算图形的面积
* @return 面积
*/
public double area();
}
// 具体的正方形
public class Square implements Shape{
private Double side;
@Override
public double area() {
return side * side;
}
}
// 具体的圆形
public class Circle implements Shape{
private Double r;
@Override
public double area() {
return Math.PI * r * r;
}
}
当新增三角形这种数据结构时,需要:仅仅需要添加三角形实现类,实现接口重写area方法即可,符合开闭原则
eg2:计算不同等级用户对应的图书价格
面向对象编程
// 获取微信读书,不同书对于不同等级用户的价格
public double getWeiXinReadBookPrice(final User user, final Book book) {
double price = book.getPrice();
switch (user.getLevel()) {
case UserLevel.SILVER: //银
return price * 0.9;
case UserLevel.GOLD: // 金
return price * 0.8;
default:
return price;
}
}
// 获取Kindle,不同书对于不同等级用户的价格
public double getKindleBookPrice(final User user, final Book book) {
double price = book.getPrice();
switch (user.getLevel()) {
case UserLevel.SILVER: //银
return price * 0.95;
case UserLevel.GOLD: // 金
return price * 0.85;
default:
return price;
}
}
如果新增用户的Level:Plantinum铂金用户,则对应的书的具体价格又不一样,两个方法都要新增case,违背了开闭原则
面向对象编程
// 定义用户等级接口
interface UserLevel {
double getWeiXinReadBookPrice(Book book);
double getKindleBookPrice(Book book);
}
// 白银用户,使用微信读书 和 Kindle读书,对应的书价
class SilverUserLevel implements UserLevel {
@Override
public double getWeiXinReadBookPrice(final Book book) {
return book.getPrice() * 0.9;
}
@Override
public double getKindleBookPrice(final Book book) {
return epub.getPrice() * 0.85;
}
}
// 黄金用户,使用微信读书 和 Kindle读书,对应的书价
class GoldUserLevel implements UserLevel {
@Override
public double getWeiXinReadBookPrice(final Book book) {
return book.getPrice() * 0.8;
}
@Override
public double getKindleBookPrice(final Book book) {
return epub.getPrice() * 0.85;
}
}
// 调用的时候,就不要使用Switch
public double getWeiXinReadBookPrice(final User user, final Book book) {
UserLevel level = user.getUserLevel()
return level.getBookPrice(book);
}
如果新增用户的Level:Plantinum铂金用户,则直接新增铂金类,实现接口,重写两个方法即可,其它地方均无需改动,遵循开闭原则