代码路漫漫,整洁伴我行
2020/10/21 5:03:45
本文主要是介绍代码路漫漫,整洁伴我行,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
许久没有写博客,偶然翻开之前的博客记录,看之前的内容感叹自己之前太菜的同时,思绪万千。
恍恍惚惚写代码已经这么久了,见过的公司,或上班,或合作,或借鉴,阅读过得代码也可以算是有一些了,有的代码不堪入目,有的就像别人评价雷军那样,代码如诗一般。
不知道你们有没有遇到过接手别人二手项目时候,宛如吃了苍蝇一样的感觉,今天主要围绕
如何做到代码清晰简洁
为什么要代码清晰简洁
代码清晰简洁的优点是什么
代码的可维护性与效率
这几点简单分享一下我对代码整洁和代码思想的一些认识,如有不足之处,请各位大佬批评指正。
一、开发者之基石 ——— 面向对象三大特性七大原则
面向对象可谓是老生常谈了,哪怕是随便来一个面试者都能随口告诉你
三大特性 封装、继承、多态
七大原则 单一、开闭、里氏替换、接口隔离、依赖导致、迪米特和聚合复用
1. 单一职责原则(Single Responsibility Principle)
每一个类应该专注于做一件事情。
2. 里氏替换原则(Liskov Substitution Principle)
超类存在的地方,子类是可以替换的。
3. 依赖倒置原则(Dependence Inversion Principle)
实现尽量依赖抽象,不依赖具体实现。
4. 接口隔离原则(Interface Segregation Principle)
应当为客户端提供尽可能小的单独的接口,而不是提供大的总的接口。
5. 迪米特法则(Law Of Demeter)
又叫最少知识原则,一个软件实体应当尽可能少的与其他实体发生相互作用。
6. 开闭原则(Open Close Principle)
面向扩展开放,面向修改关闭。
7. 组合/聚合复用原则(Composite/Aggregate Reuse Principle CARP)
尽量使用合成/聚合达到复用,尽量少用继承。原则: 一个类中有另一个类的对象。
整体看来,用最简单的一个词语概括就是解耦,在日常的开发任务之中做不到解耦的代码,在维护起来一定是很痛苦的,举例说明如下。
//公共请求方法(方法1) methodQuery(methodModel) { // 全局赋值 this.methodModel = methodModel // 取值 let { loadingName, methodName, methodVal, pMehtod, callBack } = methodModel // 判断是执行函数还是promise let baseMethod = pMehtod ? pMehtod : this[methodName](methodVal) // loading loadingName && (this[loadingName] = true) // 请求 baseMethod && baseMethod.then(res => { this.callBackThen(res) }) .catch(() => { loadingName && (this[loadingName] = false) }) }, //promise回调(方法2) callBackThen(res) { // 取值 let { callBack, notReset } = this.methodModel // 回调函数 callBack && this[callBack](res) // 关闭动作 this.closeClass() // 刷新表格 !notReset && this.resetPostTableBody() }, //关闭动作(方法3) closeClass(openMessage, mark) { // 取值 let { loadingName, message, closeMarkName } = this.methodModel // 关闭的数组 let markArr = mark ? mark : [closeMarkName, loadingName] // 关闭标记 markArr.forEach(element => { element && (this[element] = false) }); // 提示消息 let endMessage = openMessage ? openMessage : message endMessage && this.$commonUtil.setMessage('success', endMessage, true) },
这个是我最开始接触前端的时候封装的一个方法,甚至当时觉得完美无瑕,一套流程下来,程序跑的顺顺当当,直到后来业务扩展,发现函数一环套一环,多余出来的逻辑无法满足,但由于项目体积过大,时间紧,只好一点点的往里边填充各种判断,和横向扩充修改,这无疑是很明显的违反了单一和开闭原则。
感谢公司信任,直到后来项目做H5 被改进了一下如下
methodQuery(model) { // loading名称 ,消息提示 , promise或方法名称 ,方法参数,回调 let { loadingName, message, pMethod, params, callBack } = model // 打开loading loadingName && (this[loadingName] = true) // 判断传进来的是promise 还是 方法名称 let method = typeof pMethod == 'string' ? this[pMethod](params) : pMethod // 操作promise method.then(async res => { message && Toast.success(message || '操作成功') // 回调方法 callBack && await this[callBack](res) }).finally(_ => { // 关闭loading loadingName && (this[loadingName] = false) }) },
又到最后从外边改成了建造者模式
我感觉这些特性和原则里边最重要的,首先合理的多态,合理的多态可以让你的代码更加灵活,下边的原则都是围绕上边的特性来讲的,假设你写了一个不参与业务的抽象方法,一个方法有多种实现和你多种方法复制多份比较起来,哪个方便维护和阅读不言而喻吧。
其次最简单的要知道一个单一原则,一个开闭原则,一个函数只做一件事,不要让自己和别人回过头来看自己代码的时候每次都要找了五分钟才能找到重点,浪费了别人的时间。
说到这里我比如吐槽一下最近二开的一个php的项目
姑且不说这大段的各种姿势的循环,我万万没有想到一个函数居然有700行之巨!!!真是不吐不快!
回忆起这番经历的时候,我只是感觉出来混早晚是要还的,或者后期维护的时候自己一边改自己的代码一边骂自己2B,或者别人改自己代码的时候骂自己是2B,而且写出方便维护的代码不会出奇奇怪怪的bug,也能更少的加班何乐而不为呢。
二、开发者之矛 ———— 设计模式的思想与清晰的目录结构划分
设计模式,记得有一次面试的时候,问到那个面试者,你常用的设计模式有哪些,然后他回答我按照网上的例子写了几次,感觉很不方便,后来就不怎么用了。
在这里我想表达的是,写代码切记不要生搬硬套,重要的是思想。
也会有人说前端不需要设计模式,这显然是不正确的,设计模式在oo社区里被广泛的应用与推广,设计模式作为设计思想,与语言无关。
简单介绍下我比较喜欢的几种设计模式 ,建造者、抽奖工厂、策略模式
策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
我对策略模式的认识说来惭愧还是因为大段的 if else 判断的情况下被老同志批评之后才认识的,当时真的是有一种豁然开朗的感觉。简单举个栗子。
go(val) { if (val === 'a') { return !!val } if (val === 'b') { console.error('123') } if (val === 'c') { return val || 'reset' } }
如上代码一个函数里边判断了四种情况,针对不同的情况去执行不同的操作,在这种情况下。
- 首先假设用户加了十种情况,那么这段代码的阅读行将会无比的差,在扩展的时候缺乏弹性。
- 其次算法的复用性差,比如其他地方有类似其中的某一种算法的时候,这部分代码不能服用,那么怎么办呢,我相信肯定会有人出现复制的想法,那么就又陷入了代码维护工作量巨大的问题。
更改后代码如下
let demoConfig = { a: 'a', b: 'b', c: 'c' } a(val) { return !!val } b() { console.error('123') } c(val) { return val || 'reset' } go(val) { let methodName = Reflect.get(demoConfig, val) methodName(val) }
那么更新之后的这段代码有什么优点呢
- 参与了更少的业务逻辑,增强各个算法的可移植性,比如可能多个地方都用到了算法a等
- 有了单独的配置项之后,可以清晰的知道,当参数是某种策略后会去做什么事情,而不是在大篇幅的代码中寻找自己想要的策略
同样为什么说设计模式是一种思想,这个思想可以用到任何适用的地方,比如表单校验,比如环境变量再比如写html厌倦了,换个口味jsx中的模板渲染。
还有不得不说的之前遇到的大段的if else 升级版 switch
const expr = 'Papayas'; switch (expr) { case 'Oranges': console.log('Oranges are $0.59 a pound.'); break; case 'Mangoes': case 'long': console.log('Mangoes and papayas are $2.79 a pound.'); // expected output: "Mangoes and papayas are $2.79 a pound." break; case 'Papayas': console.log('Mangoes and papayas are $2.79 a pound.'); // expected output: "Mangoes and papayas are $2.79 a pound." break; case 'Oranges': console.log('Oranges are $0.59 a pound.'); break; default: console.log(`Sorry, we are out of ${expr}.`); }
之前抽象工厂和建造者写过博客就不赘述了
抽象工厂点击传送门
建造者模式 点击传送门
这两种设计模式属于创建型模式,个人认为这种创建型模式,很适用于那种重复功能且中规中矩定制的外包项目,前期花一些时间,把各个代码工厂零件写好之后,通篇配置项就可以完成一个完整的产品,举个例子,A的商城中需要订单、购物车、商品列表,B的企业官网需要商品列表、文章列表,C的博客站需要文章列表、书籍商品列表、购物车
那么我们完全没有必要去做重复的工作把每一份代码都重新定制一遍。
或许你会说这三个项目每个项目都有自己独立的逻辑,生搬硬套肯定不使用,这又要讲到另一个思想,叫做依赖注入,控制反转。
为什么前边说要尽可能吧把业务和基础拆分开,就前端而言,写ui的时候颗粒度一定要尽可能的细化,你的组件和页面模板不参与业务,我们只需要写出使用的业务注入到页面模板当中去达到我们要的业务就可以了。
再比如说现在git上边那么多的开源的各种ui组件库,各种的开源的网站生成器,代码生成器等等等等,我想他们在做项目的时候肯定不会说每一个项目都要重新写一遍的那种。
所以总结来说,写代码最关键的是一个思想的问题。
一个清晰的目录结构,写起代码起来事倍功半,拿vue举例
- 组件
- 页面
- 工具类
- 混入
- 请求层
- 中间件层
- 业务层
- 枚举
- 静态资源
- 初始化 扫描等配置
还有里边的细化,业务组件,基础组件,业务方法,基础方法,能否公用之类的
之前写的一个仿vue-cli的脚手架 zjs-template-cli 有node 环境的话直接
npm i zjs-template-cli -g zjs-cli init demo
就可以生成一个vue的脚手架,也是之前刚接触前端的时候做的,大佬们多多批评,最近会更新一版ts的到这个上边,喜欢的可以试试哦~~~ (^▽^)
开发者之盾 ———— 防御性编程的意识
防御性编程(Defensive programming)是一种具体体现,它是为了保证,对程序的不可预见的使用,不会造成程序功能上的损坏。它可以被看作是为了减少或消除墨菲定律效力的想法。防御式编程主要用于可能被滥用,恶作剧或无意地造成灾难性影响的程序上。
上边这句话摘自百度百科
首先来聊一下什么叫做防御性编程,个人愚见防御性编程的这种意识,是对我们开发者的一个保护,在开发项目中避免我们遇到许多莫名其妙的不在预期之中的问题,是减少bug和提高工作效率的一个意识。
我之前是做了有快两年的财务项目,简单分享一个之前的项目过程
不小心点了发布 如有不足大佬们请批评指正 明天继续补上 喜欢的点个赞吧..
这篇关于代码路漫漫,整洁伴我行的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-27前端高频面试题详解与实战攻略
- 2024-12-27前端高频面试真题解析与实战指南
- 2024-12-27前端面试实战:初级工程师必备技巧与案例分析
- 2024-12-27前端面试题及答案:新手必备指南
- 2024-12-27前端面试真题及答案解析:初级前端工程师必备指南
- 2024-12-25前端大厂面试真题解析与实战攻略
- 2024-12-25如何准备前端面试:新手指南
- 2024-12-25前端面试题详解与实战攻略
- 2024-12-25前端面试真题详解与实战攻略
- 2024-12-252024前端大厂面试真题详解及备考指南