换个角度看 设计模式

645 阅读11分钟

重点

说到设计模式很多人会把他和面向对象关联起来, 其实我想说的是设计模式和面向对象没有什么必然的关系.

开篇词

首先我们要了解设计模式是什么, 面向对象又是什么, 为什么设计模式和面向对象没有必然的关系

设计模式: 这是一种思想, 如何实现,用什么实现并不重要, 好比做菜, 蒸、炸、煎、炒、煮你用什么烹饪方式不重要, 重要的是做出好吃的菜

面向对象: 这是一种范式, 如 面向过程、面向对象、函数式编程... 等等, 以后还会出现更多的范式、大家只是写法不同, 每个范式都是一种书写方式而已.

举几个🌰

适配模式:

适配模式顾名思义 就是适配器, 我们现实中使用的适配器应该不少大家都在用, 3.55mm耳机接口 转 type-c 就是大家采用的一种适配器, 还比如MacBook 外接显示器 键盘鼠标, 等等如果是有线的话,也都得通过适配器.

那么在代码中那里会用到呢?

举个🌰: 公司服务端分了好多组, 什么交易中心、 商品中心、 用户中心.... 等等.

造成了苦逼的前端, 这直接导致一个页面可能需要好多组提供接口,和对接的人变多了, 接口字段定义难免混乱. 最近一个场景: 类目接口原本是商品中心提供的, 获取一级, 再获取二级 三级....,

这时候产品说: 我们发布商品的时候,用户只能选中他自己下面的经营类目.

那么一级类目就不能从商品中心获取了,就从用户中心获取了, 果然他们的字段命名不一样.

怎么办? 这时候当然要写一个方法把用户中心获取的数据改为和商品中心定义的字段一样,才能保证后面的逻辑照样执行. 那么这个方法就是适配模式, 这样说大家是不是瞬间发现原来如此, 我也经常用的嘛.

装饰器

es6里就有装饰器这东东, 那么什么叫装饰器, 就是我写一个方法,给目标方法套一层.

比如, 我们大多数人知道的防抖节流等方法, 都会给目标方法套一层,放回一个新的方法, 这就是一种装饰器

也就是不影响方法原有功能给其添加上新的功能的一个方法.

举个🌰: 最近一个场景, 产品说商品在申请精选的审核期间, 我们不能让他点击编辑和删除这些操作,点击后就弹出提示框.

大多数人的写法就是直接那那个几个方法里加上提示框的逻辑. 我不,我偏不, 我就不想改原来的代码.

怎么办? 当然是写一个方法, 把其他几个方面名字写在当前方法的一个数组里, 循环数组, 直接修改掉原来的方法, 我们看到商品在审核状态就提示弹窗, 不然就运行原来的方法, 那么我们这个功能怎么办都不会影响到原来的方法, 后来交互师又把这个交互下了,我只要把这个方法一删就好, 添加不影响,删除也安心的删

阶段性总结一下

从上面可以看到, 各种设计模式都是为了达成一种目标, 用什么范式编写并没什么必然的联系.

学习设计模式主要搞清楚 他想要干什么, 而不是说他怎么写, 你只知道他怎么写一辈子也用不上, 因为你不知道他要干什么 你就不会用起来.

现在你可以重新翻开你的设计模式书籍去找找, 各种设计模式是干什么的

个人比较喜欢的几种原则

单一性、开放性、封闭性

很多人看到 开放性、和封闭性 就有点蒙逼了, 感觉有点冲突这两点.

这些问题我们在后面的🌰来说明.

🌰嘿: 咖啡机例子:

单一性: 如果我们做一个咖啡机, 我们要做 美式咖啡、拿铁、卡布奇诺..., 于是我们写了三个方法.

我们又要加一种咖啡, 我们又要写了一种方法.

我们来看 咖啡机基本就是咖啡豆、奶、糖等东西的不同配比, 我们是不是能不能写几个基础方法供一个制作咖啡的方法使用. 一个获取咖啡豆、奶、糖、搅拌、这些方法

而几种制作咖啡的方法只要调用这几种方法,传递获取的量就好, 是不是再加一种咖啡就变的很简单了

开放性: 需求千奇百怪, 市场需要什么抹茶咖啡、芥末、香蕉、等等的味道,怎么办, 我们在咖啡机上加插槽吗, 再写几个基础方法,获取抹茶、芥末、香蕉等等? 又来新品种怎么办?

既然是咖啡机, 那么我们只关心咖啡, 其他不管, 就是这么任性. 咖啡机只有一个放咖啡的插槽. 方法就是获取咖啡, 对外暴露三四个管子, 分别写 获取A B C D管的内容, 什么抹茶、奶这些都放外面, 你要加啥加啥, 我不管, 用户自己加, 那么有新的品种, 用户换个材料就好, 这样做显然用户 操作变麻烦了, 用户需要, 输入, 获取多少咖啡, 获取A管多少, B管多少... 搅拌... 那么封闭性就登场了

封闭性: 用户每次那么麻烦当然不愿意、 我们可以给个创建咖啡菜单功能、

创建一个美式: 获取咖啡

创建拿铁: 获取咖啡、获取A管(少奶)、获取B管(糖水);

创建卡布奇诺: 获取咖啡、获取A管(多奶)、获取B管(糖水);

创建抹茶: 获取咖啡、获取A管(少奶)、获取C管(抹茶).... 等等

那么一个咖啡菜单就生成了, 有新品种用户只需加一次配方, 用的时候打开菜单,点击需要的咖啡就可以生成一杯需要的咖啡了

写组件的工具库等内容就需要考虑到开发性和封闭性、毕竟你写的再多,也总有你考虑不到的地方, 就算你把所有场景都写进去,你的代码还能维护吗,包会不会很大;

所有我们开axios会提供拦截params等方法,让你自己可以改造请求参数, 返回参数;

jq提供自定义方法

vue提供自定义指令

eslint 提供自定义规则 .....

单一性,日常开发中是一个比较常用的规则;

🌰: 创建商品事件, 通常有 参数的各种校验 请求 请求成功后 等等

我通常写方法会写一个 给按钮绑定的事件 用来处理整体逻辑过程的, 通常会有 改变按钮 loading 发起请求的一个函数 在把loading改回来 然后重新获取列表 或一些请求完成后需要调用的一些方法

有人说就这一点代码需要分开 几个方法吗, 一起也就十几二十来行.

没错,单从这一次开发来说, 说的没什么问题: 通常我们开发, 需要改原来的代码怎么做, 直接往这个方法里继续塞代码, 不管多长也不会去拆分, 所以我们第一次就需要把整体结构定义出来,使后续的人能在照自己的结构走.

嗯好像有道理, 那么一些比较活跃的功能,变更需求比较多, 也会很快把几个方法变大怎么办? 后面在讲

同样的道理一个页面也一样, 我发现很多页面就是一个vue文件或react文件等等

一个文件开始五六百、 经过需求变更到了 1千 1千5 2千, 不断膨胀, 对后面的维护者来说,瑟瑟发抖. 生怕一不小心就是一个bug

为什么会膨胀这么多,需求变更有加功能,废弃功能,和修改原有功能?

我们再看我们面对这些需求变更是怎么做的, 通常加功能就是怼代码, 废弃功能, 面对这么多代码通常就是把按钮注释了,下面的逻辑不删, 怕删出bug, 不动他就不会有bug, 修改原有功能, 通常也是能不动就不动原来的代码,尽量是往原方法里加代码, 膨胀..膨胀..膨胀... 炸裂

原因在哪, 代码太多不管动, 代码少时, 还能看的懂的时候容易改的时候不拆分. 当然我也不会去拆分, 为什么我不去拆分,没有强制要求,当然不会去拆了, 虽然代码少的时候去读代码也得要时间, 当然这点时间对后期膨胀到不敢下手来说还是有必要的.

那么谁来强制要求拆分组件和方法呢? 又怎么保证持续性呢?

eslint

eslint 是个好东西. 开始我一点都不喜欢他, 他很妨碍我开发效率, 什么空格、换行、分号...等等很烦

相信好多人开始也有这种感觉, 个人感觉这种细节对代码可读性毫无帮助, 对代码格式一致性说实话也没太大帮助, 通常把这些无关紧要的校验关闭就不在影响我们的开发了

以vue为例:

代码的结构一致性: 可以规定 html components minxs props data compute watch methods mounted created css 这样的一个大体的结构,一旦结构一致, 那么维护者就能快速找到对呀的内容

如果eslint的规定 就会出现各种大家喜好的排列, 规定后也许不符合很多人的喜好, 但是过一段时间,大家的喜好就一致了, 代码的整体结构也就一致了

文件的拆分和方法的拆分: eslint 规定了文件最大行数和方法的最大行数, 那么就必然会强迫团队在代码要超过标准时会去梳理逻辑进行拆分, 方法同理, 也许开始的时候团队拆分的不够好, 如果拆分的不好, 数据的传递必然困难,不好用, 那么在书写时必然会去寻找更合理的拆分方法, 随着不断的练习和团队的讨论,必然能找到一个合理的拆分方案. 这时整个团队的书写方式也更加契合了. 同样也规避了文件过于膨胀带来的一种不愿动它的心情

举两个拆分方式的🌰:

后台表格类型界面: 二次封装过的组件, 通过参数传递创建界面, 相信很多人有类似的组件.

主页面 一个表格组件, 一个config.js 设置页面显示内容(查询, 表格, 也就是主要掌控显示内容)

主页面中 有各种操作按钮, 表格类型界面通常 通常以弹窗按钮为主, 每个弹窗一个文件, 主页面按钮只负责打开弹窗 操作具体内容归各自文件处理

其他类型界面: 一个客服聊天界面, 一个聊天框, 和右侧的一些快捷回复等等, 快捷回复列表和聊天框怎么交互呢?

点击快捷回复列表, 组件对外提供click 事件, 事件接受 聊天的文案

聊天框对外接受 聊天文案, 主页面需要把接受到的内容传递给聊天框组件, 至于聊天框拿到外部给他的数据要怎么做就是他自己的事了, 主页面并不管

重点: 这里的聊天框输入有去拿主页面传递过来的聊天数据, 并不是说,聊天框平时输入的文本变量就在主页面, 而是在他自己的文件中, 接受到外部给的数据, 是添加到现有的变量上还是覆盖,就是他自己的事了

还是一样,各自文件负责自己的功能,外部需要该文件提供什么数据,提供一下, 通过主页面协调, 主页面并不参与文件负责功能的具体功能

当然有优秀的拆分方法, 乐于探讨学习