刚工作的时候,学习并整理了《JavaScript常见设计模式实践梳理》,那会还运用了一些比较基础的设计模式在代码里,比如:模版方法模式、策略模式、发布-订阅模式,以及装饰器模式。
最近又重学了一遍设计模式,复习了“一小时读完《JavaScript设计模式与开发实践》”,学了极客时间的《设计模式之美》、掘金小册《JavaScript 设计模式核心原理与应用实践》,再结合自己在写代码时的思考,获益良多。
感觉自己平时使用的较多的还是发布-订阅模式,但在一些复杂状态、组件复用的情况下,还是需要更多的设计模式来进行辅助让代码的层次得以提升,状态模式和装饰器模式很好用。
《设计模式之美》里用的示例虽然是Java代码,但是会有一些通用的概念。对于里面提到的设计原则、编程规范、以及代码重构都很值得学习。
设计模式分类:
我们常把23种经典的设计模式分为三类:创建型、结构型、行为型。
- 创建型设计模式主要解决“对象的创建”问题;
- 结构型设计模式主要解决“类或对象的组合或组装”问题;
- 行为型设计模式主要解决的就是“类或对象之间的交互”问题。
关于重构:
- 我们可以把重构理解为,在保持功能不变的前提下,利用设计思想、原则、模式、编程规范等理论来优化代码,修改设计上的不足,提高代码质量。
- 资深工程师为代码质量负责,需要发觉代码存在的问题,重构代码,时刻保证代码质量处于一个可控的状态。
- 我特别提倡的重构策略是持续重构,就像把单元测试、Code Review作为开发的一部分,我们如果能把持续重构也作为开发的一部分,成为一种开发习惯,对项目、对自己都会很有好处。时刻具有持续重构意识,才能避免开发初期就过度设计,避免代码维护的过程中质量的下降。而那些看到别人代码有点瑕疵就一顿乱骂,或者花尽心思去构思一个完美设计的人,往往都是因为没有树立正确的代码质量观,没有持续重构意识。
- 不过,保持代码质量最好的方法还是打造一种好的技术氛围,以此来驱动大家主动去关注代码质量,持续重构代码。
关于编码技巧:
- 将复杂的逻辑提炼拆分成函数和类。
- 通过拆分成多个函数或将参数封装为对象的方式,来处理参数过多的情况。
- 函数中不要使用参数来做代码执行逻辑的控制。
- 函数设计要职责单一。
- 移除过深的嵌套层次,方法包括:去掉多余的if或else语句,使用continue、break、return关键字提前退出嵌套,调整执行顺序来减少嵌套,将部分嵌套逻辑抽象成函数。
- 用字面常量取代魔法数。
- 用解释性变量来解释复杂表达式,以此提高代码可读性。
SOLID原则:
设计原则 | 解释 |
---|---|
单一职责原则 (SRP) | Single Responsibility Principle,每个类应该只有一个引起其变化的原因,即一个类只负责一个功能领域。 |
开放封闭原则 (OCP) | Open/Closed Principle,软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。即不改变现有代码的情况下,通过扩展实现新功能。 |
里氏替换原则 (LSP) | Liskov Substitution Principle,子类对象必须能够替换其父类对象而不引起错误或不良行为,这样利用继承实现系统时,子类对象就可以完全替代父类对象。 |
接口隔离原则 (ISP) | Interface Segregation Principle,客户端不应该被强迫依赖它们不使用的方法,通过多个专门的接口而不是一个通用接口来实现系统的灵活性和解耦。 |
依赖倒置原则 (DIP) | Dependency Inversion Principle,高层模块不应该依赖低层模块,两者都应该依赖于抽象。抽象不应该依赖细节,细节应该依赖抽象。 |
其它设计原则:
设计原则 | 解释 |
---|---|
别重复自己(DRY)原则 | Don't Repeat Yourself,不要重复代码或逻辑。当某个逻辑需要在多个地方使用时,应将其提取到一个单独的模块或函数中。 |
保持简单(KISS)原则 | Keep It Simple and Stupid,保持设计简单,避免不必要的复杂性,以提高代码的可读性、可维护性和可扩展性。 |
你不会需要它(YAGNI)原则 | You Aren't Gonna Need It,只实现当前需要的功能,不要为了未来可能需要的功能进行过度设计和实现。 |
最少知识原则(LOD法则) | Law of Demeter,一个对象应该对其他对象有最少的了解,只与直接的朋友(相关联的对象)通信,避免和陌生的对象发生联系,以减少耦合度。 |
高内聚 | High Cohesion:模块内部相关性强,所有功能都是高相关的,应当集中在一起。一个高内聚的模块通常专注于完成一个单一任务,能够独立工作。高内聚提高了系统的可维护性与可重用性。 |
松耦合 | Loose Coupling:模块之间的依赖关系较少,每个模块可以独立演变和修改而不影响其他模块。耦合度低使得系统组件之间的变化不会引起连锁反应,增进了系统的灵活性和可扩展性。 |
代码重构 (Refactoring) | 通过逐步修改代码结构而不改变其行为,以提高代码的可读性、可维护性和性能。 |
持续集成 (CI) | Continuous Integration:开发人员频繁地集成他们的工作,并自动化测试和构建,以快速发现问题和保持高质量的软件产品。 |
领域驱动设计 (DDD) | Domain-Driven Design:以领域模型为核心,通过紧密结合业务领域和需求将软件设计分为不同领域,关注领域逻辑和领域模型的正确性。 |
测试驱动开发 (TDD) | Test-Driven Development:首先编写测试用例,通过测试驱动开发,确保代码实现功能之前要通过测试验证,提升代码的可靠性和可维护性。 |
行为驱动开发 (BDD) | Behavior-Driven Development:基于 TDD 的一种扩展,通过定义业务行为和预期结果来驱动开发,确保开发过程符合业务需求。 |
架构风格 | Architecture Style:软件架构模式的选择和应用,如 MVC、微服务、事件驱动架构等,以满足特定的设计需求和架构目标。 |
用户体验设计 (UX Design) | 强调从用户体验出发进行设计,关注用户的交互逻辑和界面设计,以提高产品的易用性和用户满意度。 |
敏捷开发 (Agile Development) | 通过迭代和增量的开发方式,灵活应对需求变化,快速交付高质量的软件产品。 |
合成/聚合复用原则 | 优先使用对象组合和聚合来实现代码复用,而不是通过继承。 |
《JavaScript设计模式核心原理与应用实践》这本掘金小册,我感觉写的非常好,适合前端开发人员学习和理解,里面的例子很通俗易懂,很容易运用到自己的代码中去。书里还提到了观察者模式与发布-订阅模式的对比,值得大家去好好看一下。
最近看一个RxJS视频的时候,里面提到了防腐层对数据格式进行转化,我感觉就是适配器模式做的事情呀~
边写代码,边思考,边重构,这种由学习到掌握到慢慢重获自信的感觉真棒呀!