重构(4)

(一)添加解释性变量,使得代码更容易理解,更容易调试,也可以方便功能复用

解释性的变量
总价格为商品总价(单价*数量)-折扣(超过100个以上的打9折)+邮费(原价的10%,50元封顶)double getTotalPrice()
{return price * quantity - max(0, quantity - 100) * price - min(quantity * price * 0.1, 50);
}double getTotalPrice()
{double baseTotalPrice = price * quantity;double discountPrice = max(0, quantity - 100) * price;double postPrice = min(quantity * price * 0.1, 50);return baseTotalPrice - discountPrice + postPrice;
}

(二)函数中bool类型的参数的优化

就是把bool给剥离出来,构成单一职责

1.原始未优化


double calcFinalAmount(double originAmount, bool isChild)
{if(isChild){return originAmount * 0.5;}else{return originAmount;}
}

2.代码简单优化

//职责不单一
double calcFinalAmount(double originAmount, bool isChild)
{double discount = isChild ? 0.5 : 1;return originAmount * discount;
}

3.根源变量单一职责

//单一职责,根源可变变量划分
double getDiscount(bool isChild)
{return isChild ? 0.5 : 1;
}
double calcFinalAmount(double originAmount, bool isChild)
{double discount = getDiscount(isChild);return originAmount * discount;
}

4.功能单一职责

//单一职责,功能划分
double calcFinalAmountForChild(double originAmount, bool isChild)
{return originAmount * 0.5;
}
double calcFinalAmountForAdult(double originAmount, bool isChild)
{return originAmount;
}

(三)令人抓狂的字符串组合

硬拼接---->变成格式化拼接

//硬拼接
std::string userInfo = "user info:" + "id: " + userId.to_string() + "Name: " + user.Name());
//格式化拼接
char data[200];
sprintf(data, "user info : id :  %s, Name :  %s", userId.to_string(), user.Name());

(四)函数复用性优化

struct Users
{int status;
};
// 函数复用性很差
Users queryUserStatusIs10();
Users queryUserStatusIs5();
// 改善复用性之后
Users queryUsersByStatus(int status);

(五)避免魔法数字

1.未优化

std::string getUserStrType()
{// 1--- child  2---adult  3---elderint userType = 0;if (userType == 0){return "child";}else if (userType == 1){return "adult";}else if (userType == 2){return "elder";}
}

优化:

enum UserType
{CHILD,ADULT,ELDER,
};std::string getUserStrType()
{// 1--- child  2---adult  3---elderUserType ut = UserType::CHILD;if (ut == UserType::CHILD){return "child";}else if (ut == UserType::ADULT){return "adult";}else if (ut == UserType::ELDER){return "elder";}
}

(六)长函数分解优化(注释驱动原则)

每当刚觉要用注释来说明解释用途的时候,这时候就需要把它抽离出来做成一个单独的函数。简单来说就是要进行功能划分,满足单一职责原则。

优化之前:

void calcMoney()
{//1. 计算总金额,如果是vip,则打95折(代码块)//2. 根据金额生成付款码{代码块)//3. 初始化付款任务{代码块)
}

优化后:

double calcSumMoney();
double generateRandomCoded(double sumPrice);
bool initTask();void calcMoney()
{//1. 计算总金额,如果是vip,则打95折(函数)double sumPrice = calcSumMoney();//2. 根据金额生成付款码{代码块)generateRandomCoded(sumPrice);//3. 初始化付款任务initTask();
}

(七)复用函数的提炼

(八)多参数函数的优化

把参数封装到结构体中。参数有可能传入错误,顺序错误,采用结构体的方法可以避免这种问题,总结来说,当参数大于等于4个,就可以采用这种方式。

1.未优化

int queryResultFromServer(strName, queryId, userID, userRegion, bIsNewVersion);

2.优化之后

可以把前4个参数,放到一个对象里面,比如结构体里面。
struct Obj
{std::string strName;int queryId;int userID;int userRegion;bool bIsNewVersion;
};
int queryResultFromServer(Obj obj);

(九)查询代替临时变量

优化前:

double getPrice()
{double basePrice = quantity * itemPrice;double discount = 1.0;if (basePrice > 1000){discount = 0.95;}return basePrice * discount;
}

优化后:

//分解为
double getBasePrice()
{return quantity* itemPrice;
}
double getDiscount()
{return getBasePrice() > 1000 ? 0.95 :0.98;
}
double getPrice()
{return getBasePrice() * getDiscount();
}

(十)数组的错误使用(属性字段)

数字改成结构体或者类,并且字段用函数来查询


class Person
{
public:Person(int age, std::string name, std::string country){m_age = age;m_name = name;m_country = country;}int getAge(){return m_age;;}std::string getName(){return m_name;}std::string getCountry(){return m_country;}private:int m_age;std::string m_name;std::string m_country;
};void printInfo(Person& person)
{printf("name: %s, age: %d, country: %s", person.getName(), person.getAge(), person.getCountry());
}

(十一)函数的副作用

1.修改任何外部的变量、对象属性和数据结构;

2.控制台输入和输出交互;

3.文件操作和网络操作

4.抛出异常或者错误终止;

//错误写法
void getMaxScore()
{arrScore = arrScore.sort();return arrScore[0];
}

传入同一个参数,得到的结果不同,这就是非纯函数,一般不能用的。

(十二) 判断函数的命名

1) is/can/could/should/need +[名词】 + 形容词,比如 isUserNotExists(); isUserIdAndAgeValid();

2) isUserValid,正逻辑, isUserNotValid,就是反逻辑。尽量使用正逻辑;

3)isUserNameAndIdValid();应该改拆成 isUserAgeValid(); isUserNameValid();,功能单一,使用起来易于扩展

(十三)硬编码,变量写死

1)把硬编码改成  常量+ 变量的字符串拼接。

2)定义成全局常量

(十四)变量命名

1)int days  写成  int elapsedTimesInDays; 什么的天;

2) 命名次数,times, 改成 timesOfRequestRetry;  究竟是对于什么的次数。

3)flag,,,改成isProcessFinished;

4)createdFiles;

(十五)区分命名

1)数字命名

//数字命名,
void copyChars(char a1[], char a2[]); 
//改成
void copyChars(char src[], char dst[]);

2)无意义的命名

class Product;  class ProductInfo;  class ProductData;

3)strName, 这时候添加类型名是多余的;

   bIsAgeValid中的b就是多余的。

    如果变量中类型名是多余的,那就不要类型名。

(十六)避免误导

1)缩写误导

       Rgb2Gray(0正确,

       setDataSta(), 这个sta就难以理解了,不是一个通用的简写方法。

       queryUserAdd(); add作者想表达是地址,但是现在用add会给人带来误导。

用简写就用通用的简写,大众不认可的不要用,不认可的情况下就用全写。

2)多义词误导

      bool setMonitorTime(); 设置监视持续多少时间?  开始时间? 监控次数?等等;

       queryRegistryContent(); register是注册表吗? 

3)变量类型误导

      class Account;

      Account[]  accountList, 这时候大家可能认为它是list的类型,容易搞混淆。

4)外形相似误导

     xyzControllerForHnadlingOfString() 和 xyzControllerForStorageOfString();

这样不仔细看,还以为是同一个函数。

    0和o比较相似; l和i和1也比较相似; 

(十七)函数中动词选用指南

1)避免滥用通用词

      getTotalAmount();  get此滥用。 

       addCharacter(); 添加一个字符,困惑,添加到头部还是尾部?

       一些词汇,创建(create,init,load),销毁(destroy,release,uninit,deinit),动词(get,fetch,load,read,write,find、serach,receive,pull),(set, write,put,push),更新(update,reset,refresh),添加/移除(add,remove,append,insert,delete);启动/停止(start,open,launch,  close,stop,finish);

(十八)函数命名动词选取

filter,mergeBy,contact, split, deduplicate, reverse, sort,fill,parse, analysis, format,convert,ensure,

(十九)代码review

1)注意

无意义的注释,过多篇幅的注释,修改代码不更新注释导致无法理解;清晰的代码是不需要过多的注释说明的,

基础的功能应该封装成代码。

函数过长,功能应该被划分。

重复代码不做复用。

按照职责设计和提炼函数,尽量做到函数的单一职责。

相同逻辑的代码积极复用。

2)典型问题

定义的时候不考虑解耦;

使用常量代替应该动态使用的内容。

3)能够在运行的时候获取的内容,不应该写死。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/67938.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spring-springboot -springcloud

目录 spring: 动态代理: spring的生命周期(bean的生命周期): SpringMvc的生命周期: SpringBoot: 自动装配: 自动装配流程: Spring中常用的注解: Spring Boot中常用的注解: SpringCloud: 1. 注册中心: 2. gateway(网关): 3. Ribbon(负载均…

DAY9,递归实现计算 :1 + 1/3 - 1/5 + 1/7 - 1/9 + .... 1/n 的值

题目 用递归实现计算 :1 1/3 - 1/5 1/7 - 1/9 .... 1/n 的值,n通过键盘输入 思路 递进阶段:n、...... 、9、7、5、3、1 函数出口:递进到1 开始返回;函数返回值视为“总和” 回归阶段:对当前n取倒数;“总…

Formality:不可读(unread)的概念

相关阅读 Formalityhttps://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482https://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482 在Formality中有时会遇到不可读(unread)这个概念,本文就将对此…

【27】Word:徐雅雯-艺术史文章❗

目录 题目​ NO1.2 NO3 NO4 NO5 NO6.7 NO8.9 NO10.11 注意:修改样式的字体颜色/字号,若中英文一致,选择所有脚本。格式相似的文本→检查多选/漏选格式刷F4重复上一步操作请❗每一步检查和保存 题目 NO1.2 F12另存为布局→行号布局…

关于ARM和汇编语言

一图流 ARM 计算机组成 输入设备 输出设备 存储设备 运算器 控制器 处理器读取内存程序执行的过程 取指阶段:控制器器通过地址总线向存储器发送想要获取的指令的地址编号,存储器将指定的指令发送给处理器 译码阶段:控制器对指令进行分…

PyTorch使用教程(9)-使用profiler进行模型性能分析

1、简介 PyTorch Profiler是一个内置的性能分析工具,可以帮助开发者定位计算资源(如CPU、GPU)的瓶颈,从而更好地优化PyTorch程序。通过捕获和分析GPU的计算、内存和带宽利用情况,能够有效识别并解决性能瓶颈。 2、原…

2025-01-22 Unity Editor 1 —— MenuItem 入门

文章目录 1 Editor 文件夹2 MenuItem3 使用示例3.1 打开网址3.2 打开文件夹3.3 Menu Toggle3.4 Menu 代码复用3.5 MenuItem 激活与失活4 代码示例 1 Editor 文件夹 ​ Editor 文件夹是 Unity 中的特殊文件夹,Unity 中所有编辑器相关的脚本都需要放置在其中&#xf…

docker 安装 mysql 详解

在平常的开发工作中,我们经常需要用到 mysql 数据库。那么在docker容器中,应该怎么安装mysql数据库呢。简单来说,第一步:拉取镜像;第二步:创建挂载目录并设置 my.conf;第三步:启动容…

linux-samba服务配置与应用

1.了解samba的配置文件 2.熟悉samba服务的实例 以前我们在windows上共享文件的话,只需右击要共享的文件夹,然后选择共享相关的选项设置即可,然后如何实现windows和linux的文件共享呢,这就涉及到了samba服务,这个软件…

Spring Boot 整合 Redis 步骤详解

文章目录 1. 引言2. 添加依赖3. 配置 Redis 连接信息4. 创建 Redis 操作服务类5. 使用 RedisTemplate 或 ReactiveRedisTemplate6. 测试 Redis 功能7. 注意事项8. 总结 Redis 是一个高性能的键值存储系统,常用于缓存、消息队列等多种场景。将 Redis 与 Spring Boot …

缓存商品、购物车(day07)

缓存菜品 问题说明 问题说明:用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大。 结果: 系统响应慢、用户体验差 实现思路 通过Redis来缓存菜品数据,减少数据库查询…

K8S中Service详解(三)

HeadLiness类型的Service 在某些场景中,开发人员可能不想使用Service提供的负载均衡功能,而希望自己来控制负载均衡策略,针对这种情况,kubernetes提供了HeadLiness Service,这类Service不会分配Cluster IP,…

npm install 报错:Command failed: git checkout 2.2.0-c

[TOC](npm install 报错:Command failed: git checkout 2.2.0-c) npm install 报错:Command failed: git checkout 2.2.0-c export NODE_HOME/usr/local/node-v14.14.0-linux-x64 npm config set registry https://registry.npmmirror.com 使用如上环…

DDD - 微服务落地的技术实践

文章目录 Pre概述如何发挥微服务的优势怎样提供微服务接口原则微服务的拆分与防腐层的设计 去中心化的数据管理数据关联查询的难题Case 1Case 2Case 3 总结 Pre DDD - 软件退化原因及案例分析 DDD - 如何运用 DDD 进行软件设计 DDD - 如何运用 DDD 进行数据库设计 DDD - 服…

通过视觉语言模型蒸馏进行 3D 形状零件分割

大家读完觉得有帮助记得关注和点赞!!!对应英文要求比较高,特此说明! Abstract This paper proposes a cross-modal distillation framework, PartDistill, which transfers 2D knowledge from vision-language models …

【大模型】ChatGPT 高效处理图片技巧使用详解

目录 一、前言 二、ChatGPT 4 图片处理介绍 2.1 ChatGPT 4 图片处理概述 2.1.1 图像识别与分类 2.1.2 图像搜索 2.1.3 图像生成 2.1.4 多模态理解 2.1.5 细粒度图像识别 2.1.6 生成式图像任务处理 2.1.7 图像与文本互动 2.2 ChatGPT 4 图片处理应用场景 三、文生图操…

从零到一:Spring Boot 与 RocketMQ 的完美集成指南

1.Rocket的概念与原理 RocketMQ 是一款由阿里巴巴开源的分布式消息中间件,最初用于支持阿里巴巴的海量业务。它基于发布-订阅模型,具备高吞吐、低延迟、高可用和强一致性的特点,适用于消息队列、大规模数据流处理等场景。以下是对 RocketMQ …

(1)STM32 USB设备开发-基础知识

开篇感谢: 【经验分享】STM32 USB相关知识扫盲 - STM32团队 ST意法半导体中文论坛 单片机学习记录_桃成蹊2.0的博客-CSDN博客 USB_不吃鱼的猫丿的博客-CSDN博客 1、USB鼠标_哔哩哔哩_bilibili usb_冰糖葫的博客-CSDN博客 USB_lqonlylove的博客-CSDN博客 USB …

没有公网IP实现seafile本地IP访问和虚拟局域网IP同时访问和上传文件

前言 Ubuntu 24.04 LTSDocker 安装 seafileOpenWrtTailscale Ubuntu 24.04 LTS 通过 docker desktop 安装 seafile 搭建个人网盘中,已经实现了本地局域网放问Ubuntu IP来访问Seafile,以及通过 Ubuntu 的 Tailscale IP 访问Seafile。但是,文…

【Uniapp-Vue3】setTabBar设置TabBar和下拉刷新API

一、setTabBar设置 uni.setTabBarItem({ index:"需要修改第几个", text:"修改后的文字内容" }) 二、tabBar的隐藏和显式 // 隐藏tabBar uni.hideTabBar(); // 显示tabBar uni.showTabBar(); 三、为tabBar右上角添加文本 uni.setTabBarBadge({ index:"…