【重构】五、 封装

通过封装,可以隐藏不需要对外暴露的信息,防止被修改

1、封装记录

参考“第一组重构”中的封装变量

2、封装集合

  • 先通过封装变量,封装集合
  • 在类上添加“添加集合元素”和 “ 移除集合元素”的函数
class Person {
	constructor(name) {
		this._name = name
		this._course = []
	}
	get name() { return this._name }
	get course() { return this._course }
	
	// 有了单独的添加和移除元素的方法,set 设置函数就没有存在的必要了
	// set course(aList) { this._course = aList}
	
	addCourse(aCourse) {
		this._course.push(aCourse)
	}
	removeCourse(aCourse, fnIfAbsent() => {throw new RangeError();}) {
		const index = this._aCourse.indexOf(aCourse)
		if(index === -1) fnIfAbsent()
		else this._course.splice(index, 1)
	}
}

	

3、以查询取代临时变量

// bad
class Order {
	constructor(quantity, item) {
		this._quantity = quantity
		this._item = item
	}
	get price() {
		// 可消灭的临时变量
		var basePrice = this._quantity * this._item.price
		// 可消灭的临时变量
		var discountFactor = 0.98
		if(basePrice > 1000) discountFactor -= 0.03
		return basePrice * discountFactor
	}
}

// good
class Order {
	constructor(quantity, item) {
		this._quantity = quantity
		this._item = item
	}
	get price() {
		return this.basePrice * this.discountFactor
	}
	get basePrice() {
		return this._quantity * this._item.price
	}
	
	get discountFactor() {
		let result = 0.98
		if(this.basePrice > 1000) result -= 0.03
		return result
	}
}

4、替换算法

// bad
function foundPerson(person) {
	for(let i = 0; i < person.length; i++) {
		if(person[i] === 'Don') {
			return 'Don'
		}
		if(person[i] === 'John') {
			return 'John'
		}
		if(person[i] === 'Mary') {
			return 'Mary'
		}
	}
}

// good
function foundPerson(person){
	const candidates = ['Don', 'John', 'Mary']
	return person.find(p => candidates.includes(p)) || ''
}

5、以函数调用取代内联代码

// bad
let appliesToMass = false
for(const s of status) {
	if(s === 'MA') appliesToMass = true
}

// good
let appliesToMass = status.includes('MA')

6、拆分循环

如果一次循环中做了多个事情,如果需要修改循环时,都需要重新理解这两件事情。

拆分循环,让一个循环只做一个事情,能让循环更容易理解以及更容易使用。

// bad 
let youngest = people[0] ?  people[0].age : Infinity
let totalSalary = 0
for(const p of people) {
	if(p.age > youngest) youngest = p.age 
	totalSalary += p.salary
}
return `youngestaAge: ${youngest}, totalSalary: ${totalSalary}`

// good
function youngestaAge() {
	let result = people[0] ?  people[0].age : Infinity
	for(const p of people) {
		if(p.age > result) result = p.age 
	
	}
	return result
}
function totalSalary() {
	let result = 0
	for(const p of people) {
		result += p.salary
	}
	return result
}
return `youngestaAge: ${youngestaAge()}, totalSalary: ${totalSalary()}`

// better
function youngestaAge() {
	return Math.min(...people.map(p => p.age))
}

function totalSalary() {
	return people.reduce((total, p) => total + p.salary, 0)
}
return `youngestaAge: ${youngestaAge()}, totalSalary: ${totalSalary()}`

7、以管道取代循环

// 数据源
office, country, telephone
Chigaco, USA, +1 312 373 1000
Beijing, China, +86 400 800 4200
Bangalore, India, +91 80 373 1000

// bad 循环体过于复杂
// 筛选出印度的所有办公室,并返回办公室所在的城市和电话
function acquireData(input) {
	const lines = input.split('/n')
	let firstLine = true
	const result = []
	for(const line of lines) {
		// 略第一行数据
		if(firstLine) {
			firstLine = false
			continue
		}
		
		// 过滤空字符串
		if(line.trim() === '') continue
		
		// 将数据转换为数组
		const record = line.split(',')
		
		// 过滤,只获取"India"相关数据
		if(record[1].trim() === 'India') {
			
			// 映射成需要的数据格式
			result.push({city: record[0].trim(), phone: record[2].trim()})
		}
	}
	return result
}

// good
function acquireData(input) {
	const lines = input.split('/n')
	return lines
		.slice(1) 	// 忽略第一行数据
		.filter(line => line.trim() === '') // 过滤空字符串
		.map(line => line.split(','))  // 将数据转换为数组
		.filter(record => record[1].trim() === 'India') // 过滤,只获取"India"相关数据
		.map(record => {{city: record[0].trim(), phone: record[2].trim()}})
}

8、移除死代码

//bad 应该移除的死代码
if(false) {
	doSomething() 
}

9、拆分变量

变量有变量的用途,如果变量承担多个责任,它应该被分解为多个变量

// bad
let temp = 2 * (height + width)
temp = height + width

// good
const perimeter = 2 * (height + width)
const area = height + width
// bad
function discount(inputValue, quantity) {
	if(inputValue > 50) inputValue = inputValue - 2
	if(quantity > 100) inputValue = inputValue - 1
	return inputValue
}

// good
function discount(inputValue, quantity) {
	let result = inputValue
	if(inputValue > 50) result = result - 2
	if(quantity > 100) result = result - 1
	return result
}

10、以查询取代派生变量

// bad -- 数据重复, 每次调用applyAdjustment 都对_production累加一次
class ProductionPlan {
	construction(production) {
		this._production = production
	}
	get production() { return this._production}
	applyAdjustment(anAdjustment) {
		this._adjustments.push(anAdjustment)
		this._production += anAdjustment.amount
	}
}


// good
class ProductionPlan {
	construction(production) {
		this._production = production
	}
	get production() { 
		return this._adjustments
			.reduce((sum, a) => sum + a.mount, 0)
	}
	applyAdjustment(anAdjustment) {
		this._adjustments.push(anAdjustment)
	}
}
  • 11
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值