动机:你有一个复杂的条件(if-then-else)语句。
做法:从if、then、else三个段落中分别提炼出独立函数。
代码1:
if(date.before(SUMMER_START) || date.after(SUMMER_END))
charge = quantity * _winterRate + _winterServiceCharge;
else charge = quantity * _summerRate;
代码2:date.before、date.after在什么时间之前,在什么时间之后
if(notSummer(date))
charge = winterCharge(quantity);
else charge = summerCharge(quantity);
private boolean notSummer(Date date){
return date.before(SUMMER_START) || date.after(SUMMER_END);
}
private double summerCharge(int quantity){
return quantity * _summerRate;
}
private double winterCharge(int quantity){
return quantity * _winterRate + winterServiceCharge;
}
代码1:
double disabilityAmout(){
if(_seniority < 2) return 0;
if(_monthsDisabled > 12) return 0;
if(_isPartTime) return 0;
}
代码2:
double disabilityAmout(){
if(isNotEligibleForDisability()) return 0;
}
boolean isNotEligibleForDisability(){
return ((_seniority < 2) || (_monthsDisabled > 12) || (_isPartTime));
}
代码1:
if(isSpecialDeal()){
total = price * 0.95;
send();
}
else{
total = price * 0.98;
send();
}
代码2:
if(isSpecialDeal())
total = price * 0.95;
else
total = price * 0.98;
send();
做法:以break语句或者return语句取代控制标记。
代码1:
void checkSeurity(String[] people){
boolean found = false;
for(int i = 0; i < people.length; i++){
if(!found){
if(people[i].equals("Don")){
sendAlert();
found = true;
}
if(people[i].equals("John")){
sendAlert();
found = true;
}
}
}
}
代码2:
void checkSeurity(String[] people){
boolean found = false;
for(int i = 0; i < people.length; i++){
if(people[i].equals("Don")){
sendAlert();
break;
}
if(people[i].equals("John")){
sendAlert();
break;
}
}
}
代码3:
void checkSeurity(String[] people){
String found = "";
for(int i = 0; i < people.length; i++){
if(found.equals("")){
if(people[i].equals("Don")){
sendAlert();
found = "Don";
}
if(people[i].equals("John")){
sendAlert();
found = "John";
}
}
}
}
代码4:
void checkSeurity(String[] people){
for(int i = 0; i < people.length; i++){
if(people[i].equals("Don")){
sendAlert();
return "Don";
}
if(people[i].equals("John")){
sendAlert();
return "John";
}
}
}
动机:函数中的条件逻辑使人难以看清正常的执行路径。
代码1:
double getPayAmount(){
double result;
if(_isDead) result = deadAmount();
else{
if(_isSeparated) result = separatedAmount();
else{
if(_isRetired) result = retiredAmount();
else result = normalPayAmount();
}
}
return result;
}
代码2:
double getPayAmount(){
if(_isDead) return deadAmount();
if(_isSeparated) return separatedAmount();
if(_isRetired) return retiredAmount();
return normalPayAmount();
}
动机:你手上有个条件表达式,它根据对象类型的不同而选择不同的行为。
做法:将这个条件表达式的每个分支放进一个子类内的覆写函数中,然后将原始函数声明为抽象函数
代码1:
class Employee..
double getSpeed(){
switch(_type){
case EUROPEAN:
return getBaseSpeed();
case AFRICAN:
return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts;
case NORWEGIAN_BLUE:
return (_isNailed) ? 0 : getBaseSpeed(_voitage);
}
throw new RuntimeException("Should be unreachable");
}
代码2:
class EmployeeType...
abstract double getSpeed();
class Engineer...
double getSpeed(){
return getBaseSpeed)();
}
class Saleman...
double getSpeed(){
return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts;
}
class Manager...
double getSpeed(){
return (_isNailed) ? 0 : getBaseSpeed(_voitage);
}
动机:你需要再三检查对象是否为Null。
代码1:if(customer == null) plan = billingPlan.basic();
else plan = customer.getPlan();
代码2:
class NullCustomer extends Customer{
public boolean isNull(){
return true;
}
}
class Customer..
public boolean isNull(){
return false;
}
如果你喜欢,也可以新建一个借口,昭告大家“这里使用了空对象”;
interface Nullable{
boolean isNull();
}
class Customer implements Nullable
我还喜欢加入一个工厂函数,专门用来创建NullCutomer对象。这样一来,用户就不必知道空对象的存在了:
class Customer...
static Customer newNull(){
return new NullCustomer();
}
示例:
class Site...
Customer getCustomer(){
return (_customer == null)?Customer.newNull():_customer;
}
Customer customer = site.getCustomer();
BillingPlan plan;
if(customer.isNull())plan = BillingPlan.basic();
else plan = customer.getPlan();
动机:某一段代码需要对程序状态做出某种假设。
做法:以断言明确表现这种假设
代码1:double getExpenseLimit(){
//should have either expense limit or primary project
return (_expenseLimit != NULL_EXPENSE)?_expenseLimit;
_primaryProject.getMemberExpenseLimit();
}
代码2:double getExpenseLimit(){
Assert.isTrue(_expenseLimit !=NULL_EXPENSE || _primaryProject !=null);
return (_expenseLimit != NULL_EXPENSE)?
_expenseLimit:
_primaryProject.getMemberExpenseLimit();
}
断言是一个条件表示,应该总是为真。如果它失败,表示程序员犯了错误,因此断言的失败应该导致一个非受控异常(unchecked exception)。断言绝对不能被系统的其他部分使用。实际上,程序最后的成品往往将断言统统删除。因此,标记“某些东西是个断言”是很重要的。
断言可以作为交流与调试的铺助。在交流的角度上,断言可以帮助程序阅读者理解代码所做的假设:在调试的角度上,断言可以再距离bug最近的地方抓住它们。
编写一个辅助类(例如Assert类)当然有所帮助,可惜的是断言参数中的任何表达式不论什么情况都一定会被执行一遍。阻止它的唯一方法就是使用类似下面的手法:
double getExpenseLimit(){
Assert.isTrue(Assert.ON && (_expenseLimit !=NULL_EXPENSE || _primaryProject !=null));
return (_expenseLimit != NULL_EXPENSE)?
_expenseLimit:
_primaryProject.getMemberExpenseLimit();
如果Assert.ON是个常量,编译器就会对它进行检查;如果它等于false,就不再执行条件表达式后半段代码。