一、软件设计六大原则

单一职责原则

  • 永远不应该有多于一个原因来改变某个类
  • 理解:对于一个类而言,应该仅有一个引起它变化的原因
  • 应用:如果一个类拥有了两种职责,那就可以将这个类分成两个类

举例:
登录页面(验证用户名和密码),其中验证用户名和密码不应该写在同一个函数中,应拆分成两个方法去实现。

开放封闭原则:

  • 软件实体扩展应该是开放的,但对于修改应该是封闭
  • 理解:对扩展开放,对修改封闭。可以去扩展类,但不要去修改类
  • 应用:当需求有改动,尽量用继承组合的方式来扩展类的功能,而不是直接修改类的代码

举例:
登录页面(在验证用户名和密码的基础上添加对图片验证码的验证,只有图片验证码验证通过后才可以验证密码),如果直接修改验证密码函数功能,则需付出大量时间对原有功能进行验证。针对这种情况,可以对原有功能进行封装,通过返回true或者false,判断是否要进行接下来的流程,最大程度上减少对原有功能的侵入。

里式替换原则:

  • 理解:父类一定能够被子类替换

注:里式替换原则在使用面向对象的时候,会着重注意到,但在使用函数式编程的时候,对于里式替换原则关注度则没那么高。

接口隔离原则:

  • 一个类与另一个类之间的依赖性,应该依赖于尽可能小的接口
  • 理解:不要对外暴露没有实际意义的接口。用户不应该依赖它不需要的接口
  • 应用:当需要对外暴露接口时,如果是非必要对外提供,尽量删除

注:什么是接口?在程序设计中通过接口去预设一部分类型来限定一个类的实现。

依赖倒置原则:

  • 高层模块不应该依赖于低层模块,它们应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
  • 理解:应该面向接口编程,不应该面向实现类编程
  • 并不是说,所有的类都要有一个对应的接口,而是说,如果有接口,那就尽量使用接口来编程吧

最少知识原则:

  • 只与你最直接的对象交流
  • 理解:低耦合、高内聚
  • 应用:做系统设计时,尽量减小依赖关系

二、其他设计原则

组合/聚合复用原则

  • 当要扩展类的功能时,优先考虑使用组合,而不是继承
  • 该原则在23种经典设计模式中频繁使用
  • 如:代理模式装饰模式适配器模式

注:在ES6中,通过装饰模式扩展类的新功能。

无环依赖原则

  • 场景:当A模块依赖于B模块,B模块依赖于C模块,C依赖于A模块,此时将出现循环依赖;
  • 在设计中避免该问题,可通过引入”中介者模式” 解决

共同封装原则

  • 应该将易变的类放在同一个包里,将变化隔离出来
  • 该原则是“开发-封闭原则”的衍生

共用重用原则

  • 如果重用了包中的一个类,那么也就相当于重用了包中的所有类,我们要尽可能减小包的大小

好莱坞原则

  • Don’t call me, I’ll call you.
  • “控制反转”(或称为”依赖注入”)
  • 不需要主动创建对象,而是由容器帮我们来创建并管理这些对象

注:inversify 这个库可以帮我们主动创建对象。

不要重复你自己

  • 不要让重复的代码到处都是,要让它们足够的重用,所以要尽可能地封装

保持它简单与傻瓜

  • 保持系统界面简洁,功能实用,操作方便

高内聚与低耦合

  • 模块内部需要做到内聚度高,模块之间需要做到耦合度低

关注点分离

  • 将一个复杂的问题分离为多个简单的问题,然后逐个解决(注:通常所说的分而治之)
  • 难点:如何进行分离

你不需要它

  • 不要一开始就把系统设计得非常复杂,不要陷入”过度设计”的深渊
  • 让系统足够简单,而又不失扩展性

三、软件设计分层

系统级架构 => 应用级架构 => 模块级架构 => 代码级架构,难度逐层递减。

WX20210706-061253.png

3.1 系统级架构

系统级架构涉及到的内容:

  • 应用在整个系统内涉及到主要内容是与后台服务如何通信,与第三方系统如何集成;
  • 设计前端首要条件需了解前端系统与其他系统之间的关系,其中关系包括业务关系和协助机制;
  • 设计后端只需要规定与后台数据传递的机制,这种机制包括API设计规则、访问授权的一个开放标准(OAuth)跳转token的验证、数据传递cookie等;
  • 前端与后端的关系考虑的主要因素:前后端分离的架构设计。前后端分离架构指的是如何实施技术决策,如用户鉴权、API接口管理和设计、API文档管理、Mock的使用、BFF(服务于前端的后端,nodejs)、是否需要服务端渲染等;

微前端是将多个前端应用以某种形式结合在一起进行应用,旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用(Frontend Monolith)后,随之而来的应用不可维护的问题。对于微前端而言,它的整体地位比较特殊:

  • 在一个系统内微前端是应用间的架构方案。但是对于整体应用而言,微前端则是一种系统间等架构方案
  • 微前端的两种实现形式:
    • 单实例:同一个时刻,只有一个子应用被展示,子应用具备一个完整的应用生命周期;
    • 多实例:同一时刻可展示多个子应用。通常基于url的变化来做子应用的切换;
  • 通常使用 Web Components 方案来做子应用封装,子应用更像是一个业务组件而不是应用;

3.2 应用级架构

应用级架构可以看作是系统级架构的细化,需考虑单个应用与其他外部应用的关系,如微服务架构下多个应用的协作、数据交换等。应用级架构使用场景如下:脚手架、模式库(比如说方法库、UI库)、设计系统(应用级架构的内部系统设计)。

3.3 模块级架构

模块级架构可以理解为我们在开始业务编码之前进行设计,这个过程也可称为迭代的过程。

3.4 代码级架构

对于代码级架构,讲得更多的是规范与原则。代码级架构内容有如下:

  • 开发流程
  • 代码质量以及改善
  • 规范而非默契

注:

  • 在开发中,要注意可维护性、可扩展性
  • 简单的代码可维护性高;越是写的抽象的代码越难维护;

参考资料