改善丑陋的代码

147 阅读1分钟

改善丑陋的代码

if-else系列——卫语句

解决问题——多个if else语句嵌套。

do{
    if(oOld > 35){
        consloe.log("Old is not suitable")
        break;
    }
    if(strMajor != "Software Engineering"){
        consloe.log("Major is not suitable")
        break;
    }
    if(!bIsPassChoose){
        consloe.log("PassChooseis not suitable")
        break;
    }
    if(!bIsPassInterview){
        consloe.log("PassInterviewis not suitable")
        break;
    }
    bIsPassed = true;
}while(false)

if-else系列——条件合并提炼

let userInfo = {name:"Jerry", id:6879, isActivated:true, status:"valid"}

function getUserInfoContent(userInfo){
    if(userInfo.name == ""){
        return "Invalid data received";
    }
    if(userInfo.id <= 0){
        return "Invalid data received";
    }
    if(userInfo.status == ""){
        return "Invalid data received";
    }
    if(!userInfo.isActivated:true){
        return "User status is not normal";
    }
    if(userInfo.status != "valid"){
        return "User status is not normal";
    }
    return "Welcome" + userInfo.name
}
 let userInfo = {name:"Jerry", id:6879, isActivated:true, status:"valid"}

function getUserInfoContent(userInfo){
    if(userInfo.name == "" || userInfo.id <= 0 || userInfo.status == ""){
        return "Invalid data received";
    }
    if(!userInfo.isActivated:true || userInfo.status != "valid"){
        return "User status is not normal";
    }  
    return "Welcome" + userInfo.name
} 
let userInfo = {name:"Jerry", id:6879, isActivated:true, status:"valid"}

function getUserInfoContent(userInfo){
    if(!isDataValid(){
        return "Invalid data received";
    }
    if(!isUserStatusNormal(){
        return "User status is not normal";
    }  
    return "Welcome" + userInfo.name
} 

function isDataValid(){
    if(userInfo.name == "" || userInfo.id <= 0 || userInfo.status == ""){
        return false;
    }
    return true;
}

function isUserStatusNormal(){
    if(!userInfo.isActivated:true || userInfo.status != "valid"){
        return false;
    }  
    return true;
}

if-else系列——表驱动

function Format(strDay){
    if(strDay=="Mon"){
        return "Monday";
    }
    else if(strDay=="Tue"){
        return "Tuesday";
    }
    else if(strDay=="Wed"){
        return "Wednesday";
    }
    else if(strDay=="Thu"){
        return "Thursday";
    }
    else if(strDay=="Fri"){
        return "Friday";
    }
    else if(strDay=="Sat"){
        return "Satarday";
    }
    else if(strDay=="Sun"){
        return "Sunday";
    }
    else{
        return "Unknown";
    }
}


function Calcualte(command,num1,num2){
    if(command == "add"){
        return num1 + num2;
    }
    else if("sub"){
        return num1 - num2;
    }
    else if("mul"){
        return num1 * num2;
    }
    else if(""div){
        return num1 / num2;
    }
    else{
        return  0
    }
}
let mapDayFormat = {
    "Mon" : "Monday",
    "Tue" : "Tuesday",
    "Wed" : "Wednesday",
    "Thu" : "Thursday",
    "Fri" : "Friday",
    "Sat" : "Satarday",
    "Sun" : "Sunday",
    "Other" : "Unknown",
}

function FormatDay(strDay){
    if (mapDayFormat[strDay]!=null){
        return mapDayFormat[strDay];
    }
    return mapDayFormatDay["Other"]
}

let mapCalculate = {
    "add":function (num1,num2){
        return num1 + num2;
    }
    "sub":function (num1,num2){
        return num1 - num2;
    }
    "mul":function (num1,num2){
        return num1 * num2;
    }
    "div":function (num1,num2){
        return num1 / num2;
    }
    "other":function (num1,num2){
        return 0;
    }
}


function Caculate(command,num1,num2){
    if(mapCalculate[command!=null]){
        mapCalculate[command](num1,num2);
    }
    return mapCalculate["other"](num1,num2);
}

if-else系列—— 策略模式

策略模式可以设置多种策略 。

let mapCalculate = {
    "add":function (num1,num2){
        return num1 + num2;
    }
    "sub":function (num1,num2){
        return num1 - num2;
    }
    "mul":function (num1,num2){
        return num1 * num2;
    }
    "div":function (num1,num2){
        return num1 / num2;
    }
    "other":function (num1,num2){
        return 0;
    }
}

function Caculate(command,num1,num2){
    if(mapCalculate[command!=null]){
        mapCalculate[command](num1,num2);
    }
    return mapCalculate["other"](num1,num2);
}
class Calculator{
    constructor(){
       this.stategy = null; 
    }
    setStrategy(stategy){
        this.stategy = stategy; 
    }
    calculateResult(){
        return this.strategy.excute(num1,num)
    }
}

class Add{
    execute(num1,num2){
        return num1 + num2;
    }
}

class Sub{
    execute(num1,num2){
        return num1 - num2;
    }
}

class Mul{
    execute(num1,num2){
        return num1 * num2;
    }
}

class Div{
    execute(num1,num2){
        return num1 / num2;
    }
}

if-else系列—— 简单工厂模式

class TeacherUser{
    constructor(){
        this.name = "teacher";
        this.permissionList = ["upload","modify","notify"];
    }
    showPermission(){
        console.log(this.permissionList);
    }
}


class StudentUser{
    constructor(){
        this.name = "student";
        this.permissionList = ["query","comment"];
    }
    showPermission(){
        console.log(this.permissionList);
    }
}


class VisitorUser{
    constructor(){
        this.name = "visitor";
        this.permissionList = ["browse"];
    }
    showPermission(){
        console.log(this.permissionList);
    }
}


let loginUserType = "visitor";
let user;
if(loginUserType === "teacher"){
    user = new TeacherUser();
}
if(loginUserType === "teacher"){
    user = new StudentUser();  
}
if(loginUserType === "teacher"){
    user = new VisitorUser();
}
user.showPermission();
class UserSimpleFactory(){
    getInstance(userType){
        let user = null;
        switch(userType){
            case "teacher":
                user = new TeacherUser();
                break;
            case "student":
                user = new StudentUser();
                break;
            case "visitor":
                user = new VisitorUser();
                break;
        }
    }
}


let loginUserType = "visitor";
let userSimpleFactor = new UserSimpleFactory();
let user = userSimpleFactory.getInstance(loginUserType);
user.showPermission()

函数命名

//如何优雅地命名函数
//1. 函数命名不应追求过于简短, 而是尽可能清晰地表达出函数的
//2. 高质量的函数命名是可以让函数体本身或是被调用出无需任何
//3. 函数命名应该偏像函数功能而非执行过程

let arrHeight = {
    {name:"xiaoming",height:172},{name:"xiaoli",height:181},
    {name:"xiaozhao",height:189}
}

//select heightest student
function QueryHeightAndCompare(arrHeightInfo){//违反3和2
    let heighestStudent="";
    let heighestValue = 0;
    for (let index=0;;index<arrHeightInfo.length;++index){
        if(arrHeightInfo[index].height > heighestValue){
            heightStudent = arrHeightInfo[index].name;
            heightValue = arrHeightInfo[index].height;
        }
    }
}

//calculate average height
function CalAverHgt(arrHeightInfo){//违反1和2
    let sumHeight = 0;
    for(let index=0;index<arrHeightInfo.length;++index){
        sumHeight = sumHeight + arrHeightInfo[index].height;
        heightestValue = arrHeightInfo[index].height;
    }
}


function showResult(heightSudent, averageHeight){//违反1,2
    console.log("Here is the result");
    console.log("Average height is : " + averageHeight + 
    "The highest student is :" + highestStudent);
}


function Fun1(){//违反1,2,3
    showResult(QueryHeightAndCompare(arrHeight),CalAverHgt(arrHeight));
}
//如何优雅地命名函数
//1. 函数命名不应追求过于简短, 而是尽可能清晰地表达出函数的
//2. 高质量的函数命名是可以让函数体本身或是被调用出无需任何
//3. 函数命名应该偏像函数功能而非执行过程
let arrHeight = {
    {name:"xiaoming",height:172},{name:"xiaoli",height:181},
    {name:"xiaozhao",height:189}
}

//select heightest student
function GetHeighestStudentName(arrHeightInfo){
    let heighestStudent="";
    let heighestValue = 0;
    for (let index=0;;index<arrHeightInfo.length;++index){
        if(arrHeightInfo[index].height > heighestValue){
            heightStudent = arrHeightInfo[index].name;
            heightValue = arrHeightInfo[index].height;
        }
    }
}

//calculate average height
function CalculateAverageHeight(arrHeightInfo){
    let sumHeight = 0;
    for(let index=0;index<arrHeightInfo.length;++index){
        sumHeight = sumHeight + arrHeightInfo[index].height;
        heightestValue = arrHeightInfo[index].height;
    }
}


function PrintHeighestStudentAndAverageHeight(heightSudent, averageHeight){
    console.log("Here is the result");
    console.log("Average height is : " + averageHeight + 
    "The highest student is :" + highestStudent);
}


function ShowHeighestStudentAndAverageHeight(){
    PrintHeighestStudentAndAverageHeight(GetHeighestStudentName(arrHeight),CalculateAverageHeight(arrHeight));
}

函数命名——判断性函数命名推荐

let userList = [
    //....
]

//判断用户是否存在
function checkUserNameExist(userName){
    //....
}

//判断用户名是否可以修改
function checkUserNameExist(userName){
    //....
}

class Hotel{
    constructor(name, destination, serviceList){

    }
    //判断宾馆是否有WIFI
    judegeWifi(){

    }
    //判断宾馆是否可以预定
    canOrderHotel(){

    }
}

普通工具和工具方法

前缀词+名词+动词(is/can/has/...+something+verb)

类方法

前缀次+名词(is/can/has/...+somethin)

前缀词

表示是否符合的状态——is

表示是否能执行的状态——can

表示是否包含的状态——has/include/contain

表示是否需要的状态——should/needs

let userList = [
    //....
]

//判断用户是否存在
function iskUserNameExist(userName){
    //....
}

//判断用户名是否可以修改
function shouldkUserNameChange(userName){
    //....
}

class Hotel{
    constructor(name, destination, serviceList){

    }
    //判断宾馆是否有WIFI
    hasWifi(){

    }
    //判断宾馆是否可以预定
    canOrder(){

    }
}

函数命名——数据获取

userInfo = {id:1233,name:"xiaoming",score:[70,56,4,32,69]}

//直接从对象,数据结构中获取数据
function getUserId(){
    return userInfo.id;
}

//通过计算获取数据
function getUserAverageScore(){

}

//数据库查找数据
function getUserName(){

}

//从配置文件中加载数据
function getUserInfo(){

}

//网络请求获取数据
function getUserInfo(){

}

直接从对象,数据结构中获取数据 ——get

通过计算获取数据——calculate/cal

数据库查找数据——find/query

从配置文件中加载数据——load(直接在某个字段)/parse(通过配置文件解析出来)/build(多个内容拼接出来)

网络请求获取数据——fetch

userInfo = {id:1233,name:"xiaoming",score:[70,56,4,32,69]}

//直接从对象,数据结构中获取数据
function getUserId(){
    return userInfo.id;
}

//通过计算获取数据
function calUserAverageScore (){ //calUserAverageScore calculateUserAverageScore

}

//数据库查找数据
function findUserName (){//findUserName queryUserName

}

//从配置文件中加载数据
function laodUserInfo (){//laodUserInfo parseUserInfo buildUserInfo

}

//网络请求获取数据
function fectchUserInfo(){//fectchUserInfo

}

引入解释性变量优化复杂语句

//总价格为商品总价(单价*数量) - 折扣(超过100个以上的打9折) + 邮费(原价的10%,50元封顶)
let orderInfo = {
    quantity : 150,
    price : 3.7
}


function getToalPrice(){
    return orderInfo.quantity * orderInfo.price
           - Math.max(0,orderInfo.quantity - 100)*orderInfo.price * 0.1
           + Math.max(orderInfo.quantity*orderInfo.price*0.1,50);
}
//总价格为商品总价(单价*数量) - 折扣(超过100个以上的打9折) + 邮费(原价的10%,50元封顶)
let orderInfo = {
    quantity : 150,
    price : 3.7
}


function getToalPrice(){
    let baseSumMonday = orderInfo.quantity * orderInfo.price;
    let discountMoney = Math.max(0,orderInfo.quantity - 100)*orderInfo.price * 0.1;
    let postMoney = Math.max(orderInfo.quantity*orderInfo.price*0.1,50);
    return baseSumMonday - discountMoney + postMoney 
}

为什么尽量少用bool型的函数参数?

  1. 可能造成函数语义不明确

  2. 函数职责不单一

j解决方法:对函数进行拆分,去除bool变量。

function calFinalAmount(originalAmount, isChild){
    if(isChild){
        return originalAmount * 0.5;
    }else{
        return originalAmount;
    }
}


function printWelcomeWords(isActivated){
    if(isActivate){
        console.log("Welcome! Please select your product");
    }else{
        console.log("Welcome! Please log in");
    }
}

//1.不可以从函数调用本身知道函数的意图,必须看代码才知道传递bool值的意义
//2. 函数职责不单一,上述连个函数毕竟要判断,还要实现其他逻辑
calFinalAmount(200,true);
printWelcomeWords(true);
function calFinalAmountForChild(originalAmount){
    return originalAmount*0.5;
}


function calFinalAmountForChild(originalAmount){
    return originalAmount;
}


function printWelcomeWordsOnActivated(){
    console.log("Welcome! Please select your product");
}


function printWelcomeWordsOnUnactivated(){
    cconsole.log("Welcome! Please log in");
}

calFinalAmountForChild(200);
calFinalAmountForChild(200);
printWelcomeWordsOnActivated();
printWelcomeWordsOnUnactivated();

字符串组合拼接

let userId = 8001;
let userName = "xiaoming";
let userToken = "a56y07g0";

function createHeaderContent(){
    let userInfo = "User Info: " + "Id: " + userId.toString() + "Name: "
        + userName + "Token: " + userToken;
    let headerContent = "start|" + userId + "|" + userName + "|" + userToken
        + "|end";
    console.log(userInfo);
    return headContent;
}

console.log(createHeaderContent());
//C++ : stringstream, snprintf
//C# : string.Format
//Java : String.format
let userId = 8001;
let userName = "xiaoming";
let userToken = "a56y07g0";

function createHeaderContent(){
    //let userInfo = "User Info: " + "Id: " + userId.toString() + "Name: "
    //    + userName + "Token: " + userToken;
    //let headerContent = "start|" + userId + "|" + userName + "|" + userToken
    //    + "|end";
    let userInfo = 'User Info : Id : ${userId.toString()} Name: ${userName} Token${userToken}';
    let headerContent = 'strat|${userId}|${userName}|${userToken}|end';
    console.log(userInfo);
    return headContent;
}

console.log(createHeaderContent());

函数可复用性的提高——状态带入

let userInfoList = [
    {userId : 1, age : 23, status: "off"},
    {userId : 2, age : 12, status: "busy"},
    {userId : 3, age : 34, status: "on"},
    {userId : 4, age : 56, status: "off"},
    {userId : 5, age : 90, status: "on"},
]


function queryUserStatusIsOn(userInfoList){
    let resUserInfo = [];
    for(let index=0;index<userInfoLisr.length;index++){
        if(userInfoList[index].status == "on"){
            resUserInfoList.push(userInfoList[index]);
        }
    }
    return resUserInfoList;
}


function queryUserStatusIsBusy(userInfoList){
    let resUserInfo = [];
    for(let index=0;index<userInfoLisr.length;index++){
        if(userInfoList[index].status == "busy"){
            resUserInfoList.push(userInfoList[index]);
        }
    }
    return resUserInfoList;
}


console.log(queryUserStatusIsOn(userInfoList));
console.log(queryUserStatusIsBusy(userInfoList));
let userInfoList = [
    {userId : 1, age : 23, status: "off"},
    {userId : 2, age : 12, status: "busy"},
    {userId : 3, age : 34, status: "on"},
    {userId : 4, age : 56, status: "off"},
    {userId : 5, age : 90, status: "on"},
]


function queryUserStatusByStatus(userInfoList,staus){
    let resUserInfo = [];
    for(let index=0;index<userInfoLisr.length;index++){
        if(userInfoList[index].status == staus){
            resUserInfoList.push(userInfoList[index]);
        }
    }
    return resUserInfoList;
}

console.log(queryUserStatusByStatus(userInfoList,"on"));

避免魔法数字

namespace AvoidMagicNumber{
    enum UserType{
        Child,
        Adult,
        Elder    
    }

    class Entrance{
        static int QueryUserType(){
            //1 ——child, 2——Adult, 3——Elder
            return userType.Child;
        }
        
        static void main(string[] args){
            int nUserType = QueryUserType();
            if(nUserType == userType.Child){
                console.Writeline("child");
            }else if(nUserType == userType.Adult){
                console.Writeline("adult");
            }else if(nUserType == userType.Elder){
                console.Writeline("elder");
            }
        }
    }
}

冗长函数分解优化——单一职责

每当感觉需要点什么来注释点什么东西的时候,我们就要把说明的东西写写到独立的函数中并为其命名。

function CalcualteMoneyAndGenRandomCode(purchaseInfo){
    //calculate sum money
    let sumMoney = 0;

    for(let index = 0;index<purchaseInfo.purchaseList.length;index++){
        sumMoney += purchaseInfo.purchaseList[index].purchaseNumber 
        * perchaseInfo.purchaseList[index].unitPrice;
    }

    if(purchaseInfo.isVip){
        sumMoney = sumMoney * 0.95;
    }


    //generate random code
    let randomCode = "";

    for(let index=0;index<6;index++){
        let randomNumber = Math.floor(Math.random(0,9)*10);
        randomCode = randomCode + randomNumber.toString();
    }

    console.log("This order's sum money is" + sumMoney);

    if(randomCode==""){
        console.log("User doesn't need safety auth");
    }else{
        console.log("User need safety auth with random code" + randomCode);
    }
}
function calculateMoney(purchaseInfo){
    //calculate sum money
    let sumMoney = 0;

    for(let index = 0;index<purchaseInfo.purchaseList.length;index++){
        sumMoney += purchaseInfo.purchaseList[index].purchaseNumber 
        * perchaseInfo.purchaseList[index].unitPrice;
    }

    if(purchaseInfo.isVip){
        sumMoney = sumMoney * 0.95;
    }

    console.log("SumMoney: "+sumMoney );
}


function genRandomCode(purchaseInfo){
    //generate random code
    let randomCode = "";

    for(let index=0;index<6;index++){
        let randomNumber = Math.floor(Math.random(0,9)*10);
        randomCode = randomCode + randomNumber.toString();
    }

    console.log("This order's sum money is" + sumMoney);

    if(randomCode==""){
        console.log("User doesn't need safety auth");
    }else{
        console.log("User need safety auth with random code" + randomCode);
    }
}

复用函数提炼——相同逻辑提取

let dailySalesVolumes = [10, 15, 13, 12, 11, 17, 20];


function FormatSalesVolumeContent(SalesVolume){
    let sumSalesVolume = 0;
    for(let i=0;i<SalesVolume.length;i++){
        sumSalesVolume = sumSalesVolume = SalesVolume[i];
    }
    let salesVolume = sumSalesVolume  / SalesVolume.length;
    return "Show the sales volume : " + salesVolume;
}


function GetNextStagePointVolume(SalesVolume){

}


function GetNextStageMinVolume(SalesVolume){

}


console.log(FormatSalesVolumeContent(dailySalesVolumes))
console.log(GetNextStagePointVolume(dailySalesVolumes))
console.log(GetNextStageMinVolume(dailySalesVolumes))

优化临时变量——查询方法

class Cashier {
    contructor(quantity, itemPrice){
        this.quantity = quantity;
        this.itemPrice = itemPrice;
    }

    getPrice(){
        let basePrice = this.quantity * this.itemPrice;
        let dicountFactor;
        if(basePrice > 1000){
            dicountFactory = 0.95;
        }else{
            discountFactor = 0.98;
        }   
        return basePrice * discountFactor; 
    }
}


let cashier1 = new Cashier(30, 40);
let cashier2 = new Cashier(30, 30);

console.log(casheri.getPrice(),casher2.getPrice());
 //将临时变量替代为查询方法可以使计算过程原子化,便于对原子化过程进行单元
 class Cashier {
    contructor(quantity, itemPrice){
        this.quantity = quantity;
        this.itemPrice = itemPrice;
    }

    getPrice(){
        let basePrice = this.getBasePrice();
        let dicountFactor;
        if(basePrice > 1000){
            dicountFactory = 0.95;
        }else{
            discountFactor = 0.98;
        }   
        return basePrice * discountFactor; 
    }

     getBasePrice(){
        return  this.quantity * this.itemPrice;
     }    
}            


let cashier1 = new Cashier(30, 40);
let cashier2 = new Cashier(30, 30);

console.log(casheri.getPrice(),casher2.getPrice());
 //将临时变量替代为查询方法可以使计算过程原子化,便于对原子化过程进行单元
 class Cashier {
    contructor(quantity, itemPrice){
        this.quantity = quantity;
        this.itemPrice = itemPrice;
    }

    getPrice(){
        let basePrice = this.getBasePrice();
        let dicountFactor = this.getDiscountFactor();
        return basePrice * discountFactor; 
    }

     getBasePrice(){
        return  this.quantity * this.itemPrice;
     }    

    getDiscountFactor(){
        if(this.getBasePrice() > 1000){
            return 0.95;
         }

         else{
            return 0.98;
         }
    }

}            


let cashier1 = new Cashier(30, 40);
let cashier2 = new Cashier(30, 30);

console.log(casheri.getPrice(),casher2.getPrice());