十一、系统

153 阅读5分钟

可读性:★★★★✰ 理解难度:★★★✰✰

概述

偌大的城市可以正常运转,这是因为每个城市都有各种组织管理不同的部分,如供水系统、供电系统、交通、执法、立法,诸如此类。有些人负责全局,有些人负责细节。

其实在大多数情况下,我们会使用大佬们开发的脚手架生成系统。很多系统层面的设计方法已经被利用其中,这篇文章可以对一些设计做出解释。

一、将系统的构造与使用分开

对于前端来说,最贴切的例子就是将开发环境和正式环境分开。

比如我们用vue-cli脚手架生成的项目,有develop和production两种运行模型,这两种运行模式采用不同的打包流程。dev环境方便开发人员调试代码,而prod环境专注于线上运行效率、并发与性能。

1.1 使用main入口

在main函数中创建系统所需的对象,再传递给应用程序,应用程序只管使用。

以vue-cli生成的项目为例,其中的main.js代码如下:

import { createApp } from 'vue'
import router from './router'
import store from './store'
import VMdEditor from '@kangc/v-md-editor'
import Antd from 'ant-design-vue'const app = createApp(App)
app.use(store)
    .use(router)
    .use(Antd)
    .use(VMdEditor)
    .mount('#app')

1.2 工厂模式

简单介绍工厂模式

用工厂方法代替new操作的一种模式。

无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们的最终目的都是为了解耦。

1.3 依赖注入

有一种强大的机制可以实现分离构造与使用,那就是依赖注入(Dependency Injection)。

控制反转(Inversion of Control)是一种思想,而依赖注入是其最典型的实现方法。

他们的最终目的都是为了解耦。

小明的故事

依赖注入的前端的应用

虽然依赖注入在面向对象的语言中是一种非常基础和常见的手段,但在前端的开发中好像没有那么明显,那么我们看在Vue中是如何利用的吧:

我们在组件中用"components"声明依赖的组件时,也是一种依赖注入。也许有人说,注入的明明是具体的组件"实现"而不是"抽象"啊? 组件B依赖组件A,但在组件B中根本没有去 new 组件A,也没有管A什么时候创建,什么时候销毁,需要怎么初始化,只是为了告诉Vue这个IoC容器:组件B依赖组件A这个事情,组件的A的 created mounted destroyed这些具体的流程和实现的管理不需要B去关心,因此这个声明可以看做是依赖了A的"抽象"。这里的"抽象"并不一定是类似Java的"Interface"这种形式。

控制反转(IoC)容器,就是统一管理各个实现如何初始化、从生到死整个过程的超级管家,Vue框架本身就干了这个事情,当你用Vue.component, Vue.use把组件注册到Vue里面的时候,这个组件的实例什么时候挂载到什么地方,都可以看作由Vue这个IoC容器来控制的。

上面说Vue的父子组件之间直接声明components是一种依赖注入,还有一个更明显的 inject provide 直接给所有后代组件都注入依赖。同样,inject/provide注入给子孙后代组件,这些后代也不用管祖先组件是怎么创建和销毁的。

选自:如何在Javascript里使用依赖注入

二、扩容

城市由城镇而来,城镇由乡村而来。一开始,道路狭窄,几乎无人涉足,随后逐渐拓宽。小型建筑和空地渐渐被更大的建筑所取代,一些地方最终矗立起摩天大楼。

一开始,供电、供水、下水、互联网等服务全部没有。随着人口和建筑密度的增加,这些服务也开始出现。

这种扩张并非全无阵痛。想想看你有多少次开着车,艰难穿行一个“道路改善”工程时,是否问过自己:“他们为什么不一开始就修条够宽的路呢?!”

不过那无论如何不可能实现。谁敢打包票说在小镇里修建一条六车道的公路并不浪费呢?谁会想要这么一条穿过他们小镇的路呢?

“一开始就做对系统”纯属神话。反之,我们应该只去实现今天的user story,然后重构,明天再扩展系统、实现新的用户故事。

那么是否完全不需要预先做好计划呢?

当然不是。

虽然不是一开始就把系统做的很复杂,但要做好把系统做的很复杂的准备。

AOP(aspect-oriented programming)

面向切面编程,可以将关注点分离成一个个切入面,或切入点。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低。

比如:我们可以封装获取后台数据的服务,以至于我们可以根据需要快速的切换ajax或axios,而不影响整体系统。

我们使用的 Vue、React框架的各种钩子函数也属于aop的范畴。

Vue框架中的Aop

vue-cli 4.0 为例,系统分离出vue.config.js(打包、代理、热加载等统一配置)、router、http请求、vuex数据管理、视图等。

正式因为这些隔离,才使得我们在开发页面时,不用去关注后端接口是否可用,页面是否刷新,页面如何跳转(配置好一次路由即可不用再关注)。

三、总结

系统也应该是整洁的,无论是各部件还是各切入面都应该清晰可辨。

在系统设计的前期,别忘了使用大概可开展工作的最简单方案。

本文参考《代码整洁之道》(Robert C. Martin著,韩磊译)。

浙江大华技术股份有限公司-软研-智慧城市产品研发部招聘高级前端,欢迎来撩,有意向可发送简历到chen_zhen@dahuatech.com,长期有效

上一篇:十、类

下一篇:十二、迭进