关于编程范式的一些思考

无论是 OOP or FP,都是为了编写出可维护、易于理解的代码。不同的范式,只是不同的设计思路,或者说不同理解的实现。

但有约定的规范,这些规范建立在对这编程范式的深刻理解之上。

OOP

  1. 多实例,在程序中它可能会被实例化多次或存在多个实例,比如:VNode, Entity, Animal 等
  2. 多态 & 继承,存在继承 & 重写的关系的时侯,比如:微前端中的 App & SubApp, DOM 中的 Element & HTMLElement & HTMLDivElement 等

设计目标:

  1. 高内聚,即所有的属性、方法都集合定义在这个对象上
  2. 低耦合,边界清晰,不混杂任何跟对象无关的属性、方法

设计原则:

  1. SRP(Single responsibility principle):单一职责,一个类或者一个模块只做一件事。

    https://s3-us-west-2.amazonaws.com/secure.notion-static.com/0dda950c-a5e4-4c38-82e8-db1ef4dd540f/Untitled.png

  2. OCP(Open Closed Principle):开放封闭,对扩展开放,对修改关闭

    https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d8a54abd-404a-4b25-a171-8516d64695ed/Untitled.png

  3. LSP(Liskov Substitution Principle):里氏替换,派生类可以扩展基类的功能,但不能改变基类原有的功能

    https://s3-us-west-2.amazonaws.com/secure.notion-static.com/bc10e792-4be1-473b-bbfc-ccec0b25778a/Untitled.png

  4. ISP(Interface Segregation Principle):接口隔离,一个接口应该拥有尽可能少的行为

    https://s3-us-west-2.amazonaws.com/secure.notion-static.com/09159e6d-7d51-4ac4-846b-13ceeacff8e0/Untitled.png

  5. DIP(Dependence Inversion Principle):依赖反转,高级模块不应该依赖低级模块,而是依赖抽象接口,通过抽象接口使用对应的低级模块

    https://s3-us-west-2.amazonaws.com/secure.notion-static.com/9d2edc6f-7d69-4319-9ae6-9026960f9cfd/Untitled.png

设计模式 Design Pattern

有许多的设计模式,都很有意思。

FP

  1. 纯逻辑/纯运算,只是执行程序逻辑/运算并返回结果,比如:sum(a, b), divide(a, b)
  2. 单一/零碎,无法统一或者归类,比如 utils, helpers, type 等

设计原则:

  1. 无副作用,不修改 Input 总是返回新的 Output,更易控制/测试,相同 input 永远返回相同的 output
  2. 单一职责,一个函数只做一件事

题外话:

很多人说 React 是 FP 的拥护者,从某种程度上来说,好像是那么回事,比如像这样:

UI = React(state) = diff(VirtualDOM) = diff(fiber)

但是 Vue 则更像是个大的 Tools set 工具集合包:

Vue = MVVM(Observer + Watcher + Deps) + VirtualDOM + EventEmitter + Filters + Directives + Component + ...

还是更喜欢 React 的设计,只做自己核心的该做的事。而不是什么都给你做了,那样虽然简单,但总觉得不是在写 JavaScript,而是在写 Vuejs。而写 React 则不会有这种感觉,写 React 会觉得就是在写 JavaScript, 而不是 React。

之前看过别人的观点说 Vuejs 更适合中小型项目,不适合大型项目。经过这几年的实践来看,我是认同的。说得没错。因为 Vuejs 带来了便利 API 的同时也带来了各种副作用,或者过度设计,是一个为了方便开发者而设计的框架。而在大型项目中,过多的 API 反而显得多余,以及不好维护。

用 React 核心开发者 Dan 的话来说,React 就是一个 View Library。而 Vue 的核心思想则是 “渐进式的 MVVM 框架”,换句话来说就是你越用东西越多。

前端 VS 后端

前端,组合优于继承。因为从 HTML 的时代开始,html 标签就开始通过组合组成 view。而 view 的渲染,本质上也是各种模块 UI 的组合。所以 hooks 优于 mixin,好用的是 hooks,而不是 mixin。

  • hooks 的优势在于,将零散的逻辑通过 FP 抽离成独立的逻辑单元,可以任意组合使用,符合前端开发和组合的直觉。
  • 而 mixin 则不然,mixin 也能完成类似的工作,但其实现的思路是 OOP 的继承,而前端许多零散的零散的功能通过继承来实现,实在是舍近求远。不仅抛弃了 FP 函数式编程的便利,更带来了 OOP 继承的滚雪球式的理解难度和维护曲线。

后端,则天生更适合使用 OOP 来设计数据模型。通过 子类和基类 来实现对象间的泛化关系,通过抽象接口和具象类来实现依赖关系。无论是数据建模,还是模型关系,OOP 都是十分完美的表达。最终再通过概念的分类,将不通的逻辑分布到不同的模块,进而实现代码的可维护性。

  • service 定义业务的抽象接口给上下游业务依赖,最终通过 business module 实现 service,做到 OOP 中的 SOLID 设计原则。
  • dto/dao/vo/entity - 通过不同的对象定义实现不同的对象功能。我认为这是 MVC 中的 M,即 model。这些对象建模十分适用 OOP 的继承设计,这些对象间通常只有细微的差别。
  • controller MVC 中的C的入口,也是前端接口逻辑的入口。

References

https://zh.wikipedia.org/zh-hans/SOLID_(面向对象设计)

https://zhuanlan.zhihu.com/p/320494053

https://zhuanlan.zhihu.com/p/41885040

posted @ 2021-08-20 00:31  月光宝盒造梦师  阅读(67)  评论(0编辑  收藏  举报