代码整洁之道--去除代码的坏味道

2020-03-31  本文已影响0人  来醉一场

1. 神秘命名(Mysterious Name)

函数改名

function circum(radius) { ... }

function circumference(radius) { ... }

变量改名

let a = height * width;

let area = height * width;

字段改名

class Organization {
    get name() { ... }
}

class Organization {
    get title() { ... }
}

2. 重复代码(Duplicated Code)

提炼函数

function printOwing(invoice) {
    printBanner();
    let outstanding = calculateOutstanding();
    
    //print details
    console.log(`name:${invoice.customer}`);
    console.log(`amount:${outstanding}`);
}

function printOwing(invoice) {
    printBanner();
    let outstanding = calculateOutstanding();
    printDetails(invoice,outstanding);
}
function printDetails(invoice,outstanding) {
    console.log(`name:${invoice.customer}`);
    console.log(`amount:${outstanding}`);   
}

移动语句 (合并重复的代码片段)

const pricingPlan = retrievePricingPlan();
const order = retreiveOrder();
let charge;
const chargePerUnit = pricingPlan.unit;

const pricingPlan = retrievePricingPlan();
const chargePerUnit = pricingPlan.unit;
const order = retreiveOrder();
let charge;

函数上移

class Employee { ... }

class Salesman extends Employee {
    get name() { ... }
}

class Engineer extends Employee {
    get name() { ... }
}

class Employee { 
    get name() { ... }
}

class Salesman extends Employee { ... }

class Engineer extends Employee { ... }

3. 过长函数(Long Function)

提炼函数

function printOwing(invoice) {
    printBanner();
    let outstanding = calculateOutstanding();
    
    //print details
    console.log(`name:${invoice.customer}`);
    console.log(`amount:${outstanding}`);
}

function printOwing(invoice) {
    printBanner();
    let outstanding = calculateOutstanding();
    printDetails(invoice,outstanding);
}
function printDetails(invoice,outstanding) {
    console.log(`name:${invoice.customer}`);
    console.log(`amount:${outstanding}`);   
}

以查询取代临时变量

const basePrice = this._quantitiy * this._itemPrice;
if (basePrice > 100) {
    return basePrice * 0.5;
}else {
    return basePrice * 0.98;
}

get basePrice(){
    this._quantitiy * this._itemPrice;
}
...

if (this.basePrice() > 100) {
    return this.basePrice() * 0.5;
}else {
    return this.basePrice() * 0.98;
}

引入参数对象:

function amountInvoiced(startDate,endDate) { ... }
function amountReceived(startDate,endDate) { ... }
function amountOverdue(startDate,endDate) { ... }

function amountInvoiced(dateRange) { ... }
function amountReceived(dateRange) { ... }
function amountOverdue(dateRange) { ... }

保持对象完整

const low = aRoom.daysTempRange.low;
const high = aRoom.daysTempRange.high;
if (aPlan.withinRange(low,high))

if (aPlan.withinRange(aRoom.daysTempRange))

以命令取代函

function score(candidate,medicalExam,scoringGuide) {
    let result = 0;
    let healthLevel = 0;
    //long body code;
}

class Scorer {
    constructor(candidate,medicalExam,scoringGuide) {
        this.candidate = candidate;
        this.medicalExam = medicalExam;
        this.scoringGuide = scoringGuide;
    }
    execute (){
        this.result = 0;
        this.healthLevel = 0;
        //long body code;
    }
}

多态取代条件表达式

switch (brid.type) {
    case "EuropeanSwallow" :
        return "average";
    case "AfricanSwallow" :
        return (bird.numberOfCoconuts > 2) ? "tired" : "average" ;
    case "NorwegianBlueParrot":
        return (bird.voltage > 100) ? "scorched" : "beautiful" ;
    default:
}

class EuropeanSwallow {
    get plumage() {
        return "average";
    }
}
class AfricanSwallow {
    get plumage() {
        return (bird.numberOfCoconuts > 2) ? "tired" : "average" ;
    }
}
class NorwegianBlueParrot {
    get plumage(){
        return (bird.voltage > 100) ? "scorched" : "beautiful" ;
    }
}

拆分循环

let averageAge = 0;
let totalSalary = 0;
for (People p : people) {
    averageAge += p.age;
    totalSalary += p.salary;
}
averageAge = averageAge / people.length;

let totalSalary = 0;
for (People p : people) {
    totalSalary = p.salary;
}

let averageAge = 0;
for (People p : people) {
    averageAge += p.age;
}
averageAge /= people.length;
  1. 过长参数列表(Long Parameter List)

移除标记参数

function setDimension(name, value) {
    if (name === "height") {
        this.height = value;
        return ;
    }
    if (name === "width") {
        this.width = value;
        return;
    }
}

function setHeight(value) { this.height = value; }
function setWidth(value) { this.width = value; }

函数组合成为

function base(aReading) { ... }
function taxableCharge(aReading) { ... }
function calculateBaseCharge(aReading) { ... }

class Reading {
    function base() { ... }
    function taxableCharge() { ... }
    function calculateBaseCharge() { ... }
}
  1. 全局数据(Global Data)

封装变量

let defaultOwner = {firstName: "Martin", lastName: "Fowler"};

let defalutOwnerData = {firstName: "Martin", lastName: "Fowler"};
function defaultOwner() { return defaultOwnerData; }
function setDefaultOwner(arg) { this.defaultOwnerData = art; }
  1. 可变数据(Mutable Data)

拆分变量

let temp = 2 * (height + width);
console.log(temp);
temp = height * width;
console.log(temp);

const perimeter = 2 * (height + width);
console.log(perimerter)
const area = height * width;
console.log(area);

将查询和修改函数分离

function getTotalOutstandingAndSendBill() {
    const result = customer.invoice.reduce((total,each)=>each.amount+total,0);
    sendBill();
    return result;
}

function totalOutstanding() {
    return customer.invoice.reduce((total,each)=>each.amount+total,0);
}
function sendBill() {
    emailGateway.send(formatBill(customer));
}

移除设置函数

class Person {
    get name() { ... }
    set name(aString) { ... }
}

class Person {
    get name() { ... }
}

以查询取代派生变量

get discountedTotal() { return this.discountedTotal; }
set discount(aNumber) {
    const old = this.discount;
    this.dicount = aNumber;
    this.discountedTotal += old - aNumber;
    
}

get discountedTotal() { return this.baseTotal - this.discount; }
set dicount(aNumber) { return this.dicount = aNumber; }
  1. 发散式变化(Divergent Change)

拆分阶段:

const orderData = orderString.split(/\s+/);
const productPrice = priceList[orderData[0].split("-")[1]];
const orderPrice = parseInt(orderData[1]) * productPrice;

const orderRecord = parseOrder(order);
const orderPrice = price(orderRecord,priceList);
function parseOrder(aString) {
    const value = aString.split(/\s+/);
    return ({
        productID: value[0].split("-")[1],
        quantity: parseInt(values[1]);
    });
}
function price(order,priceList) {
    return order.quantity * priceList[order.productID];
}

搬移函数:

class Account {
    get overdraftCharge() { ... }
}

class AccountType {
    get overdraftCharge() { ... }
}

提炼类:

class Person {
    get officeAreaCode() { return this.officeAreaCode; }
    get officeNumber() { return this.officeNumber; }
}

class Person {
    get officeAreaCode() { return this.telephoneNumber.areaCode; }
    get officeNumber() { return this.telephoneNumber.number; }
}
class TelephoneNumber {
    get areaCode() { return this.areaCode; }
    get number() { return this.number; }
}
  1. 霰弹式修改(Shotgun Surgery)

搬移字段:

class Customer {
    get plan() { return this.plan; }
    get discountRate() { return this.dicountRate; }
}

class Customer {
    get plan() { return this.plan; }
    get dicountRate() { return this.plan.dicountRate; }
}

函数组合成变换:

function base(aReading) { ... }
function taxableCharge(aReading) { ... }

function enrichReading(argReading) {
    const aReading = this.cloneDeep(argReading);
    aReading.baseCharge = base(aReading);
    aReading.taxableCharge = taxableCharge(aReading);
    return aReading;
}

内联函数:

function getRating(driver) {
    retur moreThanFiveLateDeliveries(deriver) ? 2 : 1;
}
function moreThanFiveLateDeliveries(driver) {
    return diver.numOfLateDeliveries > 5;
}

function getRating(driver){
    return (diver.numOflateDeliveries > 5) ? 2 : 1;
}

内联类 (反射重构:提炼类):

class Person {
    get officeAreaCode() { return this.telephoneNumber.areaCode; }
    get officeNumber() { return this.telephoneNumber.number; }
}
class TelephoneNumber {
    get areaCode() { return this.areaCode; }
    get number() { return this.number; }
}

class Person {
    get officeAreaCode() { return this.officeAreaCode; }
    get officeNumber() { return this.officeNumber; }
}
  1. 依恋情结(Feature Envy)
  1. 数据泥团(Data Clumps)
  1. 基本类型偏执(Primitive Obsession)

以对象取代基本类型

orders.filter(o => "height" === o.priority || "rush" === o.priority);

orders.filter(o => o.priority.higherThan(ne Priority("normal")));

以子类取代类型码

function createEmployee(name, type) {
    return new Employee(name, type);
}

function createEmployee(name, type) {
    switch(type) {
        case "engineer": return new Engineer(name);
        case "salesman": return new Salesman(name);
        case "manager": return new Manager(name);
    }
}
  1. 重复的 switch(Repeated Switches)
  1. 循环语句(Loops)

以管道取代循环

const names = [];
for (Object obj : input) {
    if (obj.job === "programmer"){
        names.push(obj.job);
    }
}

const names = input.filter(i => i.job === "programmer")
                   .map(i => i.name);
  1. 冗赘的元素(Lazy Element)

折叠继承体系

class Employee { ... }
class Salesman extends Employee { ... }

class Employee { ... }
  1. 夸夸其谈通用性(Speculative Generality)
  1. 临时字段(Temporary Field)
if (aCustomer === "unknown") customerName = "occupant"; 

class UnknownCustomer {
    get name() { return "occupant" };
}
  1. 过长的消息链(Message Chains)
  1. 中间人(Middle Man)
manager = aPerson.mananger;
class Person {
    get manager() { return this.department.manager; }
}

manager = aPerson.department.manager;

以委托取代超类

class List { ... }
class Stack extends List { ... }

class Stack {
    construtor() {
        this._storage = new List();
    }
}
class List { ... }

以委托取代子类

class Order {
    get daysToShip() {
        return this._warehouse.daysToShip;
    }
}
class PriorityOrder extends Order {
    get daysToShip() {
        return this._priorityPlan.daysToShip;
    }
}

class Order {
    get daysToShip() {
        return (this._priorityDelegate) 
            ? this._priorityDelegate.daysToShip
            : this._warehouse.daysToShip;                            
    }
}
class PriorityOrderDelegate {
    get daysToShip() {
        return this._priorityPlan.daysToShip;
    }
}
  1. 内幕交易(Insider Trading)
  1. 过大的类(Large Class)
  1. 异曲同工的类(Alternative Classes with Different Interfaces)
  1. 纯数据类(Data Class)
  1. 被拒绝的遗赠(Refused Bequest)
  1. 注释(Comments)
上一篇 下一篇

猜你喜欢

热点阅读