1、分解条件表达式
变量有变量的用途,如果变量承担多个责任,它应该被分解为多个变量
// bad
if(!aDate.isBefore(plan.summerStart) && !aDate.isAfter(plan.summerEnd)){
charge = quantity * plan.summerRate
} else {
charge = quantity * plan.regularRate + plan.regularSericeCharge
}
// good
function summer() {
return !aDate.isBefore(plan.summerStart) && !aDate.isAfter(plan.summerEnd)
}
functionm summerCharge() {
return quantity * plan.summerRate
}
functionm regularCharge() {
return quantity * plan.regularRate + plan.regularSericeCharge
}
charge = summer() ? summerCharge() : regularCharge()
2、合并条件表达式
// bad -- 当一连串的条件检查都返回同一个的结果时,可以合并条件
function disabilityAmount(anEmployee) {
if(anEmployee.seniority < 2) return 0
if(anEmployee.monthsDisabled > 12) return 0
if(anEmployee.isPartTime) return 0
// doSomething
}
// good
function isNotEligibleFordisability(anEmployee) {
return (anEmployee.seniority < 2)
|| (anEmployee.monthsDisabled > 12)
|| (anEmployee.isPartTime)
}
function disabilityAmount(anEmployee) {
if(isNotEligibleFordisability()) return 0
// doSomething
}
// bad
if(anEmployee.onVaction){
if(anEmployee.seniority > 10) {
return 1
}
return 0.5
}
// good
if(anEmployee.onVaction
&& (anEmployee.seniority > 10)) return 1
return 0.5
3、以卫语句取代嵌套条件表达式
如果某个条件极其罕见,就应该单独检查改条件,并在该条件为真时立刻从函数中返回,这样的单独检查被称为“卫语句”
function payAmount(employee) {
let result
if(employee.isSeperated) {
result = {amount: 0, reasonCode: 'SEP'}
}
else {
if(employee.isRetired) {
result = { amount: 0, reasonCode: 'RET' }
}
else {
// doSomething
}
}
return result
}
// good
function payAmount(employee) {
let result
if(employee.isSeperated) return {amount: 0, reasonCode: 'SEP'}
if(employee.isRetired) result = { amount: 0, reasonCode: 'RET' }
// doSomething
return result
}
将条件反转
function adjustedCapital(anInstrument) {
let result = 0
if(anInstrument.capital > 0) {
if(anInstrument.interesRate > 0 && anInstrument.duration > 0) {
result = (anInstrument.income / anInstrument.duration) * anInstrument.adjustmentFactor
}
}
return result
}
function adjustedCapital(anInstrument) {
if(anInstrument.capital <= 0
|| anInstrument.interesRate <=0
|| anInstrument.duration <= 0) return 0
return (anInstrument.income / anInstrument.duration) * anInstrument.adjustmentFactor
}
4、以多态取代条件表达式
// bad
// 判断鸟儿的羽毛是什么颜色,以及速度有多快
// 鸟儿羽毛的颜色
function plumages(birds) {
return new Map(birds.map{b => b.name, plumage(b)})
}
// 鸟儿的速度
function speeds(birds) {
return new Map(birds.map{b => b.name, airSpeedVelocity(b)})
}
function plumage(bird) {
switch(bird.type) {
case 'EuropeanSwallow'
return 'average'
case 'AfricanSwallow'
return (bird.numberOfCocounts > 2) ? 'tired' : 'average'
case 'NorwegianBlueParrot'
return (bird.voltage > 100) ? 'scorched' : 'beautiful'
default:
return 'unknown'
}
}
function airSpeedVelocity(bird) {
switch(bird.type) {
case 'EuropeanSwallow'
return 35
case 'AfricanSwallow'
return 40 - 2 * bird.numberOfCocounts
case 'NorwegianBlueParrot'
return (bird.isNailed) ? 0 : 10 + bird.voltage / 10
default:
return null
}
}
// good -- 建立超类,由子类具体返回各自的羽毛和速度,switch 方法只需判断创建对应的子类
function plumages(birds) {
return new Map(birds
.map(b => createBird(bird))
.map(bird => [bird.name, bird.plumage]))
}
function speeds(birds) {
return new Map(birds
.map(b => createBird(bird))
.map(bird => [bird.name, bird.airSpeedVelocity]))
}
function createBird(bird) {
switch(bird.type) {
case 'EuropeanSwallow'
return new EuropeanSwallow(bird)
case 'AfricanSwallow'
return new AfricanSwallow(bird)
case 'NorwegianBlueParrot'
return new NorwegianBlueParrot(bird)
default:
return new Bird(bird)
}
}
class Bird {
constructor(birdObject) {
Object.assign(this, birdObject)
}
get plumage() {
return 'unknown'
}
get airSpeedVelocity() {
return null
}
}
class EuropeanSwallow extends Bird {
get plumage() {
return 'average'
}
get airSpeedVelocity() {
return 35
}
}
class AfricanSwallow extends Bird {
get plumage() {
return (this.numberOfCocounts > 2) ? 'tired' : 'average'
}
get airSpeedVelocity() {
return 40 - 2 * this.numberOfCocounts
}
}
class NorwegianBlueParrot extends Bird {
get plumage() {
return (this.voltage > 100) ? 'scorched' : 'beautiful'
}
get airSpeedVelocity() {
return (this.isNailed) ? 0 : 10 + this.voltage / 10
}
}