短
函数的第一准则是短, 第二准则是比刚才那个函数还要短.
public static String renderPageWithSetupAndTeardowns(
PageData pageData, boolean isSuite
) throws Exception {
boolean isTestPage = pageData.hasAttribute("Test");
if (isTestPage) {
WikiPage testPage = pageData.getWikiPage();
StringBuffer newPageContent = new StringBuffer();
includeSetupPages(testPage, newPageContent, isSuite);
newPageContent.append(pageData.getContent());
includeTeardownPages(testPage, newPageContent, isSuite);
pageData.setContent(newPageContent.toString());
}
return pageData.getHtml();
}
vs
public static String renderPageWithSetupAndTeardowns(
PageData pageData, boolean isSuite
) throws Exception {
boolean isTestPage = pageData.hasAttribute("Test");
if (isTestPage(pageData)) {
includeSetupAndTeardownPages(pageData, isSuite);
}
return pageData.getHtml();
}
只做一件事
这意味这, if, else, while中的代码块应该为一行, 这一行可能是一个函数调用.
这不仅能够让函数变得更小, 由于函数名的存在, 还能增加文档效果.
这也意味着函数不应该支持大的嵌套结构, 函数内部的缩进不应该超过两个.
判断一个函数是否做一件事情的方式是ToParagraph
去描述函数
TO RenderPageWithSetupsAndTeardowns, we check to see whether the page is a test page and if so, we include the setups and teardowns. In either case we render the page in HTML.
如果一个函数只包含处于一个层级的一系列步骤的话, 那么他就是干一件事.
毕竟, 函数的存在就是为了将一个概念拆解为下一层级当中的一些列步骤.
减少分支语句
分支语句会让函数变得很大. 尽管无法摆脱, 我们可以保证每一个分支语句是一个更底层的类. 为了做到这一点, 可以使用多态.
public Money calculatePay(Employee e)
throws InvalidEmployeeType {
switch (e.type) {
case COMMISSIONED:
return calculateCommissionedPay(e);
case HOURLY:
return calculateHourlyPay(e);
default:
throw new InvalidEmployeeType(e.type);
}
}
这个函数的坏处如下:
- 每新增一个对象, 这个函数就会变大.
- 它干了不止一件事.
- 为非烦了单一职责原则, 因为有不止一个原因去改变这个函数.
- 违反了开闭原则, 因为只要有新的类型, 这个函数就必须改变.
解决方案是用一个抽象工厂隐藏这些逻辑.
public abstract class Employee {
public abstract boolean isPayDay();
public abstract Money calculatePay();
public abstract void deliverPay(Money pay);
}
-----------
public interface EmployeeFactory {
public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType;
-----------
public class EmployeeFactoryImpl implements EmployeeFactory {
public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType {
switch (r.type) {
case COMMISSIONED:
return new CommissionedEmployee(r);
case HOURLY:
return new HourlyEmployee(r);
default:
throw new InvalidEmployeeType(r.type);
}
}
}
没有副作用
一个函数应该只做一件由它名字所体现的事情, 不应该有隐藏的逻辑.
命令/查询分离
函数不能即执行命令, 又负责查询.