Skip to content
快速预览

函数的编写

✍️ w 🕒 2023-07-23 12:23:51(10 months ago) 🔗 G.设计模式
  1. 函数名应该是一个动词或动词短语,表示函数的作用和功能。

  2. 函数应该尽量保持简短,只做一件事情,并且只有一个返回值。

  3. 函数的参数应该尽量少,最好不要超过 4 个。如果参数过多,可以考虑将参数封装成一个对象。甚至可以考虑是否应该使用 职责单一,是否能通过拆分成多个函数的方式来减少参数

java
public User getUser(String username, String telephone, String email);

// 拆分成多个函数
public User getUserByUsername(String username);
public User getUserByTelephone(String telephone);
public User getUserByEmail(String email);
  1. 函数应该尽量避免副作用,即不要修改函数外部的变量或状态。

  2. 函数应该尽量避免使用全局变量,因为全局变量会增加代码的复杂度和不可预测性。

  3. 函数应该尽量避免使用嵌套,因为嵌套会增加代码的复杂度和不可读性。

  4. 函数应该尽量避免使用过长的参数列表,可以使用默认参数或者参数对象的方式来简化参数列表。

  5. 函数应该尽量避免使用复杂的控制流程,可以使用早返回或者异常处理的方式来简化控制流程。

  6. 函数应该尽量避免使用魔法数字或者魔法字符串,可以使用常量或者枚举来代替。例如在代码中出现了数字 7,但是不清楚这个数字的含义是什么。这样的代码不仅难以理解,而且在修改时容易出错。为了避免这种情况,我们可以使用常量或者枚举来代替魔法数字或者魔法字符串。常量和枚举都可以为数字或字符串赋予明确的含义,使得代码更加易读、易懂。例如,我们可以定义一个常量 MAX_LENGTH 来表示字符串的最大长度,或者定义一个枚举来表示一组相关的常量。

java
public double CalculateCircularArea(double radius) {
  return (3.1415) * radius * radius;
}

// 常量替代魔法数字
public static final Double PI = 3.1415;
public double CalculateCircularArea(double radius) {
  return PI * radius * radius;
}
  1. 函数应该尽量避免使用复杂的表达式,可以使用中间变量或者函数来简化表达式。

函数在起名的时候还可以配合参数名字组合,例如下面方法checkUserIfExisting 检查用户是否存在,至于根据具体什么判断根据传入参数名就可以判断上,根据 手机号 用户名 邮箱 判断用户是否存在

java
public boolean checkUserIfExisting(String telephone, String username, String email)

建议上函数的代码行数不要超过一屏幕的大小,比如 50 行甚至可以理解为把函数写短,越短越好。对于比较长的函数,为了让逻辑更加清晰,可以使用空行来分割各个代码块。在类内部,成员变量与函数之间、静态成员变量与普通成员变量之间、函数之间,甚至成员变量之间,都可以通过添加空行的方式,让不同模块的代码之间的界限更加明确

注意勿用函数参数来控制逻辑

不要在函数中使用布尔类型的标识参数来控制内部逻辑,true 的时候走这块逻辑,false 的时候走另一块逻辑。这明显违背了单一职责原则和接口隔离原则。一般拆分为两个函数,这种手法叫做移除标记参数(Remove Flag Argument)

java
public void buyCourse(long userId, long courseId, boolean isVip);

// 将其拆分成两个函数
public void buyCourse(long userId, long courseId);
public void buyCourseForVip(long userId, long courseId);

或者例如除了布尔类型作为标识参数来控制逻辑的情况外,还有一种“根据参数是否为 null”来控制逻辑的情况。针对这种情况,我们也应该将其拆分成多个函数。拆分之后的函数职责更明确,不容易用错。

java
public List<Transaction> selectTransactions(Long userId, Date startDate, Date endDate) {
  if (startDate != null && endDate != null) {
    // 查询两个时间区间的transactions
  }
  if (startDate != null && endDate == null) {
    // 查询startDate之后的所有transactions
  }
  if (startDate == null && endDate != null) {
    // 查询endDate之前的所有transactions
  }
  if (startDate == null && endDate == null) {
    // 查询所有的transactions
  }
}

// 拆分成多个public函数,更加清晰、易用
public List<Transaction> selectTransactionsBetween(Long userId, Date startDate, Date endDate) {
  return selectTransactions(userId, startDate, endDate);
}

public List<Transaction> selectTransactionsStartWith(Long userId, Date startDate) {
  return selectTransactions(userId, startDate, null);
}

public List<Transaction> selectTransactionsEndWith(Long userId, Date endDate) {
  return selectTransactions(userId, null, endDate);
}

public List<Transaction> selectAllTransactions(Long userId) {
  return selectTransactions(userId, null, null);
}

private List<Transaction> selectTransactions(Long userId, Date startDate, Date endDate) {
  // ...
}

Released under the MIT License.