重构-改善既有代码的设计

重构 改善既有代码设计

章11 重构API

将查询函数和修改函数分离

动机:任何有返回值的函数,都不应该有看得到的副作用。

一种常见的优化办法是:将查询所得记过缓存于某个字段中,后续重复代码查询可以大大加快速度。

  1. 复制函数,以查询来命名
  2. 移除有副作用的代码
  3. 执行静态检查
  4. 查找所有调用原函数的地方,替换为新设计图制作软件函数,并在下面调用一次原函数
  5. 从原函数中去掉设计制造中国第一架飞机的人是返回值
  6. 测试

Before:

// Miscreant - 恶的
function alertForMiscreant(people) {
for (重构图片const p of people) {
if (设计图制作软件p === "Don") {
setOffAlarms();
return "Don";
}
if (p === "John") {
setOffAlar设计院ms();
return设计类专业 "John";
}
}
return "";
}
const found = aler代码表白tForMiscreant(people);

Aft设计签名er:

function findMiscreant(people) {
for (const p of people) {
if (p === "Don") {
return "Don";
}
if (p设计类专业 === "John") {
return "John";
}
}
return "";
}
function alertForMiscreant(people) {
if (findMiscreant(people) !== "") setOffAlarms();改善脸部凹陷的小妙招 // 替换算法
}
const found = findMiscreant(people);
alertForMiscreant(people);

函数参数化

动机:两个函重构模具生物专攻数逻辑非常相似,可以将其合并为一个函数,以参数形式传入不同值,从而消除重复。

  1. 从一组相似函数选则一个
  2. 把需要作为参数传入的字面量添加到参数列表
  3. 修改该函数所有调用改善地方
  4. 测试
  5. 修改函数体,令其使用新传入代码编程入门的参数
  6. 替换与其相似的函数,并测试

Before:

function baseCharge(usage) {
if (usage < 0) return usd(0);
const amount =
bottomB重构模具生物专攻and(usag重构色彩e) * 0.03 + middleBand(usage)代码零九 * 0.05 + to改善睡眠的9个方法pBand(usage) * 0.07;
return usd(amount);
}
functio重构n bottomBand(usage) {
return Math.min(usage, 100);
}
function middleBand(usage) {
return usage > 100 ? Math.min(usage, 200) -重构设计 100 : 0;
}
function topBa改善皮肤暗黄的5种方法nd(usage) {
return usage > 200 ? usage - 200 : 0;
}

After:

function with改善英语inBand(usage, bottom, to改善睡眠的小偏方p) {
return usage > bottom ? Math.min(usage, top) - bottom : 0;
}
function baseCha代码大全rge(usage) {
if (usage < 0) return usd(0);
const amo设计制造中国第一架飞机的人是unt =
withinBand(usage, 0, 100) * 0.03 +
withinBan设计制造中国第一架飞机的人是d(usage, 100, 200) * 0.05 +
withinBand(usage, 200, Infinity) * 0.07;
return usd(amount);
}

移除标记参数

动机重构模具生物专攻:用标记参数来指示被调函数应该执行哪一部分逻辑,影响了函数内部控制流。移除标记参数是代码更加整洁。

  1. 针对参数的每一种可能值,新建一个明确函数
  2. 修改调用函数的地方为新建明确函数

Before:

function deliveryDate(anOrder, isRush) {
if (isRush) {
let deliveryTime;
if (["MA", "CT"].includes(anOrder.deliveryState)) deliveryTime = 1;
else设计图制作软件 if (["NY", "NH"].includes(anOrder.deliveryState)) deliveryTime = 2;
else deliveryTime = 3;
return anOrder.placedOn.plusDays(1 + deliveryTime);
} else {
let deliveryTime;
if (["MA", "CT"改善英语, "NY"].inclu改善脑供血的中成药des(anOrder.del重构iveryState))代码软件 deliveryTime = 2;
else if (["ME", "NH"].includes(anOrder.deliveryState)) deliveryTime = 3;
else deliveryTime = 4;
return anOrder.placedOn.plusDays(2 + deliveryTime);
}代码编程教学
}

After重构法:

function del代码怎么学iveryDate(anOrder重构图形, isRush) {
if (isRush) return rushDeli设计制造中国第一架飞机的人是veryDate(anOrder);
else return regularDeliveryDate(anOrder);
}
function rushDeliveryDate(anOrder) {
let deliveryTime;
if (["MA", "CT"].includes(anOrder.deliveryState)) deliveryTime = 1;
else if (["NY", "NH"].includes(anOrder.deliveryState)) deliveryTime代码怎么学 = 2;
else deliveryTime = 3;
return anOrder.重构素描图片placedOn.plusDays(1 + deliveryTime);重构是什么意思
}
function regularDeliveryDate(anOrder) {代码表情包
let deliveryTime;
if (["改善视力的57种方法MA", "CT", "NY"].includ设计师怎么学es(anOrder.deliveryState设计图)) deliveryTi设计me = 2;
else if (["ME", "NH"].includes(anOrder.deliveryState)) deliveryTime = 3改善睡眠的小偏方;
else deliveryTime = 4;
return anOrder.placedOn.plusDays(2 + deli代码零九veryTime);
}

保持对象完整

动机:如果一个函数需要传入一个对象的多个属性值,传递对象本身是更好地方式。

  1. 新建空函数,传入对象改善脸部凹陷的小妙招
  2. 新函数中调设计用旧函数,并设计师证怎么考把新参数映射到就的参数列表
  3. 执行静态检查
  4. 修改调用地方为新函重构
  5. 把旧函数内联到新函数体内
  6. 修改函数名为旧改善视力的57种方法函数名,并修改所有调用的地方

Before:

const lo重构设计w = aR重构图片oom.daysTempRange.low;
const high = aRoom.daysTemp重构设计Range.high;
if (代码大全!aPlan.withinRange(l设计图ow, high))
alerts.push("room temperature went outside range");
class Heati代码编程教学ngPlan {
withinRan改善脑供血的中成药ge(bottom, top) {
return (
bottom >= this._temperatureRange.low代码软件 && top <= this._temperatureRange.high
);
}
}

After:

if (!aPlan.withinRange(aRoo改善皮肤暗黄的5种方法m.daysTemRange))
alerts.push("room temperature went outside rang重构模具生物专攻e");
class HeatingPl改善脸部凹陷的小妙招an {
withinRange(aNumberRange) {
return (
aNumberRange.low >= this._temperatureRange.low &&
aNumberRange.high <= thi设计类专业s._temperatureRange.high
);
}
}

以查询取代参数

动机:如果函数的一个参数只需要向另一个参数查询就能得到,则参数列表应避免重复。

  1. 如有必要使用提炼函数将参数的查询过程提炼到一个独立函数中
  2. 将函数重构模具生物专攻体内参数饮用的地方改为调用新建的函数,并测试
  3. 将参数去掉

Before:

class代码怎么学 Order {
get finalPrice() {
const basePrice = this.quantity * this.itemPri改善睡眠质量最好的方法ce;
let discountLevel;
if (this.quantity > 100) discountLevel = 2;
else discountLevel = 1;
return this.disc设计图制作软件ountedPrice(basePrice, discountLevel);
}
discountedPrice(bas重构素描ePrice, disc重构ountLevel) {
switch (discountLevel设计图制作软件) {
case 1:
return basePric重构是什么意思e *设计图制作软件 0.95;
ca重构设计se 2:
return basePrice * 0.9;
}
}
}

After:

class Order {
get finalPrice() {
const basePric重构是什么意思e = this.quantity * this.设计图itemPrice;
return this.discountedPrice(basePrice);
}
get discountLevel() {
return thi代码编程入门s.quantity > 100 ? 2 : 1;
}
d设计房子的软件iscountedPrice(basePrice) {
switch (discountLevel) {
case 1:
return basePrice * 0.95;
case 2:
return basePrice * 0.9;
}
}
}

以参数取代查询

动机:在负责逻辑处理的模块中只有纯函数,其外再包裹处理 I/O 和其他可变元素的逻辑代码,使其更容易测试及理解。JavaSc设计签名ript 的类模型无法强制要求类重构图形的不可变形——始终有办法修改对象的内部数据,以参数取代码编程入门代查询是达成让类保持不可变的利器。

  1. 对查询操作的代码提炼为变量,从函数体中分离出去
  2. 提炼函数体内代码为新函数
  3. 使用内联变量消除刚提炼出来的变量
  4. 对原函数使用内联函数
  5. 新函数该会原函数名字

Before:

class HeatingPlan {
get targetTemperature() {
if (thermosta改善皮肤暗黄的5种方法t.selectedTemperature > this._ma重构素描x) return this._max;
else if (thermostat.selectedTemperature <代码表情包; this._min) return this._min;
els代码大全e return thermostat.selectedTemperature;
}
}
if (thePlan.targetTemperature > thermostat.curre改善ntTemperature) s设计院etToH;
else if (t改善脸部凹陷的小妙招hePlan.targetTemperatur改善睡眠的9个方法e < thermostat.currentTemperature) setToC;
else setOff();

After:

class HeatingPlan {
targetTemperature(selecte重构dTemperature) {
if (改善selectedTemperature > this._max) return重构素描图片 this._ma设计院x;
e代码编程入门lse if (selectedTemperature < this._min) return this._min;
else retu代码怎么学rn selectedTemperature;
}
}
if (
thePlan.t重构素描图片argetTemperature(thermostat.selectedTemperature) >
thermo代码软件stat.currentTemperature
)
setToHeat();
else if (代码软件
thePla重构设计n.targetTem设计图perature(thermostat.selectedTemperature) <
thermost代码零九at.currentTemperatur改善便秘的方法e
)
setToCool();
else setOff();

移除设设计签名值函数

动机:如果不希望在对象创建之后某个代码表情包属性还有机会被改变,就不要为它提供 set 函数。

  1. 在构造函数中调用设值函数,对字段设值
  2. 移除所有在构造函数之外对设值函数的调用,改为使用新的构造函数,重构图形并测代码大全
  3. 使用内联函数消去设置函数
  4. 测试

Befor改善英语e:

class Person {
get name() {
return this._name改善睡眠质量最好的方法;代码怎么学
}
set name(arg) {
t改善便秘的方法his._name = arg;
}设计院
get id() {
return this._id;
}
set id(arg) {
this._id = arg;
}
}
const martin = new Per代码怎么编写son();
martin.na设计房子的软件me = "martin";
martin.id =重构是什么意思 "1234";

After:

class Person {
co代码软件nstructor(id) {
this._id = id;
}
get name() {
return this._name;
}
set name(arg) {
this._name = arg;
}
get id() {
return this._id;
}设计师怎么学
}
const martin = new Person("1234");
mart代码软件in.name = "marti重构是什么意思n";

以工厂函数取代构造函代码表白

动机:与一般函数相比,构造函数常有改善睡眠质量最好的方法一些丑陋的局限性,只能返回当前所调用类代码零九的实设计签名例,构造函数名称是固定的设计类专业类名,需要通改善睡眠质量最好的方法过特殊操作符调用。工厂函数的实现内部可以调用构造函数,也可以换别的方式实现。

  1. 新建一个工厂函数,让它调用现有的构造函数
  2. 将调用构造函数的代码替换为工厂函数
  3. 每次修改,执行测试
  4. 尽量缩小构造函数可见范围

Before:

class Employee {
constructor(name, typeCode代码大全) {
this._name = name;
this._typeCode = t代码图片ypeCode;
}改善脸部下垂的秘方
g改善脸部下垂的秘方et name() {
return this._name;
}
g设计房子的软件et type() {
return Employee.legalTypeCodes[this._typeCode];
}
static get legalTypeCodes() {
return { E改善便秘的方法: "Eng代码表白ineer", M: "Manager", S: "Salesman" };
}
}
const candidate = new Employee(document.name, document.empType);
const l设计房子的软件eadEngineer = new Emp重构记忆loyee(document.leadEnginee重构法r, "E"改善脑供血的中成药);

After:

class Employee {
constructor(name, typeCode) {
this._name = name;
this._typeCode = typeCode;
}
get name() {
ret改善视力的57种方法urn this._name;
}
get t改善英语ype() {
return Employee.legalTypeCodes[this._type重构Code];
}
static get legalTypeCodes() {
return { E: "Engineer", M: "Manager", S: "Salesman" };
}
}
function createEmployee(name, typeCo设计师证怎么考de) {
return new Employee(name, ty代码表情包peCode);
}
con代码怎么学st candida改善脸部凹陷的小妙招te =重构法 createEmployee(document.name, document.empType);
function createEngineer(name) {
return new Employee(name, "E");
}
const leadEngineer =设计师证怎么考 createEngineer(document.leadEngineer);

以命令取代函数

动机:将函数封装成自己的对象,称为“命令对象”,简称“命令”,只服务设计师于单一函数,获得对该函数的请求,执行函数。

  1. 为想要包装的函数创建一个空类,根据该函数名字命名
  2. 把函数移动到空类里
  3. 给每个参数创建一个字段,代码软件并在构造函数中添加对代码编程教学应的参数

Before:

function score(改善视力的57种方法candidate, medicalExam, scoringGuide) {
let result = 0;
let healthLevel = 0;
let highMedicalRiskFlag = false;
if (medicalExam.isSmoker)设计师证怎么考 {
healthL重构evel += 10;
highMedicalRiskFlag = true;
}
let cert改善脑供血的中成药ificat设计院ionGrade = "regular";
if (scoringGuide.改善便秘的方法stateWithLowCertification(candida重构模具生物专攻te.originState)) {
certificationGrade = "low";
result -= 5;
}
// lots more code like this
result -= Math.max(healthLevel - 5, 0);
return result;
}

After:

function score(candidate, med代码软件ica重构设计lExam, scoringGuide) {
return new Scorer().execute(candidate, medicalExam, scoringGui改善皮肤暗黄的5种方法de);
}
class S重构色彩corer {
constructor(candidate, medicalExam, scoringGuide) {
this._candidate设计图 = candidate;
this._medicalExam = medica设计师证怎么考lExam;
this._scoringGuide = scoringGuide;
}
execute() {
th改善皮肤暗黄的5种方法is._result = 0;
this._healthLevel = 0;
this._highMedicalRiskF设计院lag = false;
this.this.scoreSmoking();
this.设计师怎么学_certificationGrade = "regular";
if (
this._scoringGuide.stateWithLowCertification(this._ca代码大全ndidate.originState)
) {
this._certificationGrade = "low";
this设计制造中国第一架飞机的人是._result -= 5;
}
// lots more code like this
this._result -= Math.max(healthLev设计制造中国第一架飞机的人是el - 5,改善睡眠的小偏方 0);改善睡眠质量最好的方法
return this._result;
}
scoreSmoking() {
if (this._medicalExam.i重构sS重构图形moker) {
this._healthLevel += 10;
this._highMedicalRiskFlag = true;
}
}
}

以函数取代命令

动机:借助命令对象可以轻松地将原本复杂的函数拆解为多个方法,彼此间通过字段共享改善脸部下垂的秘方状态,拆解后的方法分别调用,开始调用前的数据状态也可以逐步构建。但如果这代码表白个函数不太复杂,可以考虑将其变回普通函数

  1. 把“创建并执行设计师命令对象”的代码单独提炼到一个函数中
  2. 对命令对象在执行阶段调用到改善睡眠的小偏方的函数,逐一使用内联函数
  3. 把构造函数的参数转移到执行函数声明中
  4. 执行函数中引用的所有字段改为使用参数,并测试
  5. 把“调用构造函数”和“调用执行函数”都内联到调用代码软件
  6. 测试
  7. 把命令类删除

B重构素描图片efore:

cl重构设计ass ChargeCalculator {
constructor(custome设计类专业r, usage, prov代码图片ider设计师证怎么考) {
this._cu重构法stomer = customer;
this._usage = usage;
this._provider = provider;
}
get baseCharge() {
return this._custo改善脑供血的中成药mer.baseRate * this._usage;
}
get charge() {
retur改善睡眠的9个方法n this.baseCharge + this._provider.connectionCharge;
}
}

After:

function charge(customer, usage, provider) {
const baseCharge = customer.baseRate * usage;
return baseCharge + provider.connectionCharge改善睡眠的小偏方;
}