1.去除重复代码
2.去除过长函数
一个函数如果需要花时间才能搞懂就需要将其提炼
(一个函数不超过80行)
3.数据泥团
(当有多个参数互相搭配,某些数据成群出现(关联性极高),可以将其封装成一个数据对象)
4.封装全局变量
(用get,set来控制避免误触)
// 封装变量操作 good
let globalData = 1
function getGlobalData() {
return globalData
}
function setGlobalData(newGlobalData){
if (!isValid(newGlobalData)) {
throw Error('Illegal input!!!')
return
}
globalData = newGlobalData
}
// 暴露方法
export {
getGlobalData,
setGlobalData
}
5.发散式变化:
函数复合多方向的功能时要将其拆开
function getPrice(order) {
// 获取基础价格
const basePrice = order.quantity * order.itemPrice
// 获取折扣
const quantityDiscount = Math.max(0, order.quantity - 500) * order.itemPrice * 0.05
// 获取运费
const shipping = Math.min(basePrice * 0.1, 100)
// 计算价格
return basePrice - quantityDiscount + shipping
}
const orderPrice = getPrice(order);
// 计算基础价格
function calBasePrice(order) {
return order.quantity * order.itemPrice
}
// 计算折扣
function calDiscount(order) {
return Math.max(0, order.quantity - 500) * order.itemPrice * 0.05
}
// 计算运费
function calShipping(basePrice) {
return Math.min(basePrice * 0.1, 100)
}
// 计算商品价格
function getPrice(order) {
return calBasePrice(order) - calDiscount(order) + calShipping(calBasePrice(order))
}
const orderPrice = getPrice(order)
6.霰弹式修改:
与发散式修改相反,同一方向的功能被分散时要将其复合
7.去除for,
用filter、map替换
8.复杂的条件逻辑&&合并条件表达式
将过于 复杂的条件/或变量 化为函数
// bad
if (!date.isBefore(plan.summberStart) && !date.isAfter(plan.summberEnd)) {
charge = quantity * plan.summerRate
} else {
charge = quantity * plan.regularRate + plan.regularServiceCharge
}
// good
if (isSummer()) {
charge = quantity * plan.summerRate
} else {
charge = quantity * plan.regularRate + plan.regularServiceCharge
}
// perfect
isSummer() ? summerCharge() : regularCharge()
9.查询函数与修改函数耦合
10.依恋情结:两个类频繁交互,可以将其所频繁交互处合并
11.基本类型偏执:
对于一个基本类型被用于各种转换计算输出不同格式,可以将其创建一个自己的基本类型
12.重复的switch:
对于switch重复出现,可提取相同元素,构建子类
13.夸夸其谈通用性
系统里存在一些 夸夸其谈通用性
的设计,常见语句就是 我们总有一天会用上的
,并因此企图以各式各样的钩子和特殊情况来处理一些非必要的事情。
比如A() B().A只是调用B的功能,美其名曰A之后有大用
14.临时字段
由于“aCustomer === 'unknown'
这是个特例情况,在这个特例情况下,就会使用到很多临时字段,或者说是特殊值字段。这种重复的判断不仅会来重复代码的问题,也会非常影响核心逻辑的代码可读性,造成理解的困难。”
class Site {
constructor(customer) {
this._customer = customer;
}
get customer() {
return this._customer;
}
}
class Customer {
constructor(data) {
this._name = data.name;
this._billingPlan = data.billingPlan;
this._paymentHistory = data.paymentHistory;
}
get name() {
return this._name;
}
get billingPlan() {
return this._billingPlan;
}
set billingPlan(arg) {
this._billingPlan = arg;
}
get paymentHistory() {
return this._paymentHistory;
}
}
// Client 1
{
const aCustomer = site.customer;
// ... lots of intervening code ...
let customerName;
if (aCustomer === 'unknown') customerName = 'occupant';
else customerName = aCustomer.name;
}
// Client 2
{
const plan = aCustomer === 'unknown' ? registry.billingPlans.basic : aCustomer.billingPlan;
}
// Client 3
{
if (aCustomer !== 'unknown') aCustomer.billingPlan = newPlan;
}
// Client 4
{
const weeksDelinquent = aCustomer === 'unknown' ? 0 : aCustomer.paymentHistory.weeksDelinquentInLastYear;
}
这里,我要把所有的重复判断逻辑都移除掉,保持核心逻辑代码的纯粹性。然后,我要把这些临时字段收拢到一个地方,进行统一管理。只在初始化时进行判断
class NullCustomer extends Customer {
constructor(data) {
super(data);
this._name = 'occupant';
this._billingPlan = { num: 0, offer: 0 };
this._paymentHistory = {
weeksDelinquentInLastYear: 0
};
}
}
// initial.js
const site = customer === 'unknown' ? new Site(new NullCustomer()) : new Site(new Customer(customer));
// Client 1
{
const aCustomer = site.customer;
// ... lots of intervening code ...
const customerName = aCustomer.name;
}
// Client 2
{
const plan = aCustomer.billingPlan;
}
// Client 3
{
}
// Client 4
{
const weeksDelinquent = aCustomer.paymentHistory.weeksDelinquentInLastYear;
}
15.内幕交易
有强依赖关系的两个类
“在这个案例里,如果要获取 Person
的部门代码 code
和部门领导 manager
都需要先获取 Person.department
。这样一来,调用者需要额外了解 Department
的接口细节,如果 Department
类修改了接口,变化会波及通过 Person
对象使用它的所有客户端。”
这种情况可直接将后者合并至前者
class Person {
constructor(name) {
this._name = name;
}
get name() {
return this._name;
}
get department() {
return this._department;
}
set department(arg) {
this._department = arg;
}
}
class Department {
get code() {
return this._code;
}
set code(arg) {
this._code = arg;
}
get manager() {
return this._manager;
}
set manager(arg) {
this._manager = arg;
}
}
class Person {
constructor(name, department) {
this._name = name;
this._department = department;
}
get name() {
return this._name;
}
get departmentCode() {
return this._department.code;
}
set departmentCode(arg) {
this._department.code = arg;
}
get manager() {
return this._department._manager;
}
set manager(arg) {
this._department._manager = arg;
}
}