组件化开发利用了面向对象的威力,易于构建规模比较大的应用并且获得比较高的可维护性,可扩展性。Vue、React厂商及社区不但提供了组件化开发的框架,而且提供了易于起步并包含了从编码、编译、测试到打包部署等功能的完整工具链,让我们广大受苦受累的同志们获得更好的开发体验和更高的开发效率。
渲染画面与处理交互是前端开发的基本任务。触发-反馈是前端开发的惯用模式,似乎开发一个功能仅需两步就完成了:监听事件,处理事件。例如用户点击按钮,页面监听事件后做一定反馈就结束了,如显示一个列表或给一个弹窗。
很多前端开发同志长期处于这种开发模式下,会形成思维定势,解决问题试图“两步解决”:监听事件,并在一个监听函数里解决所有问题。这样的逻辑链条很短,如果遇到复杂的业务逻辑,就会发现束手无策。即使MVVM框架提供了许多便利,但是对于一些复杂逻辑,强交互逻辑,还是需要有一定的程序设计,实现足够多的逻辑链条来支撑功能实现。
MVVM框架主打优势就是数据驱动视图。数据改变视图自动改变,这让我们可以只关注于对数据的操作,并自动获得视图符合预期的渲染(美好愿望)。视图渲染变成了数据操作的副作用,关注点分离,定义式的逻辑也很方便好用。
视图的载体是组件,组件的职责是渲染视图,Vue/React可以让组件根据数据自动渲染。
但组件也有须自主执行的逻辑,比如维护自身状态,接受交互,处理数据等。许多时候,组件不仅仅因为数据而变化,比如组件A发生了点击事件,而组件B需要做出反馈。
一般有几种方式可以让这种需求实现。
1.组件A改变了数据,数据驱动B改变。
2.组件A想办法获得组件B的实例,调用其方法使其改变。
3.组件A给组件B发送消息,B监听后改变。
MVVM框架让我们可以很容易通过第一种方式来实现。但数据驱动并不是银弹。如果数据改变引发组件B预先定义的视图发生改变,但如何使组件B执行一些计算逻辑呢?组件B可以通过监听数据变化方式来触发这些逻辑,但是数据驱动与组件内部触发特定逻辑的衔接并不顺畅。
第二种方式非常的直接,不过耦合性比较高。第三种方式耦合性低,但是消息的发送和监听的逻辑不在一个地方,可维护性会差一点。
数据驱动不能解决所有问题,所以大部分同志都综合运用三种方式来实现功能。当然也有其他的一些方式,不过基本都是上述三种方式的变种。
组件化开发,还是要使用面向对象程序设计的方法,大概就是识别对象以及它们之间的职责链。可以使用鲁棒图来帮助进行初步分析。当确定好要实现哪些组件,那么要给出这些组件的定义。入参,状态,方法,事件等。一般认为,方法代表这个组件因为什么改变或如何改变,事件代表组件通知调用方或外部发生了什么。
设计原则可以帮助我们合理的划分组件以及定义组件的职责。七大设计原则牢记于心。这里罗列一下帮助大家加强记忆。
开闭原则(对修改关闭,对扩展开放)。
单一职责原则(只干一个事)。
里氏替换原则(用到的地方,子类都能替代)。
依赖倒转原则(模块之间通过接口缔结在一起)。
接口隔离原则(只让你知道该知道的,只让你用允许你用的)。
组合/聚合复用原则(优先使用组合,而不是继承)。
最小值知识原则(知道的越少越好)。
另外可维护性,可扩展性,高内聚低耦合也是我们要关注的。
设计模式是我们解决特定问题的一些惯用做法的总结。其实我们在平时的开发过程中几乎都或多或少的接触或使用过。
大量组件可以根据一个数据源而变化,这就是享元模式,MVVM框架天然的实现了这种模式。
Promise的多个then可以链接起来处理数据,这就是一种责任链模式。
Web的富文本编辑的API document.execCommand 的典型的命令模式。我只管发送命令,至于编辑器如何改变,浏览器会去做。命令模式虽然就是调用函数,但是命令模式比较强调调用行为的原子化,参数的规范化,进而可以实现录制和撤销操作。
迭代器模式就是我们写一个循环去读取、处理集合/列表的数据。就这么朴实无华
观察者模式就是大家熟悉的事件总线或消息总线,巴拉巴拉还有很多其他说法。node的event emitter模块可以用来实现观察者模式。
许多组件通过树形结构组成一个大的组件,并且对外可以使用统一的接口进行交互就是组合模式。递归是常用的实现手段。
我们常常要对已有的模块做一个封装,就是装饰模式,我们也习惯称之为包装。
如果一个模块内部逻辑很复杂,用到了很多库等等,但是提供一个简单的接口可以让外界使用,这就是门面模式。
js对象是基于原型链继承的这就是原型模式。
单例模式比较常见,大家估计都用过。
Vue的数据驱动的原理是使用了js的Proxy语法,这就是代理模式。
当我们从服务端拉取的数据不能直接使用,需要处理一下再使用的时候,就用到了适配器模式。
状态模式有点难理解,并不是我们定义MVVM中的状态就是在使用状态模式了。这里的状态模式是将状态抽象为一个状态类,并且定义这个状态类下的行为。处于某一个状态,调用其方法就实现这个状态下的功能。这种面向对象的思维许多前端开发同学不是很熟悉。
策略模式类似于的ifelse,但是这里的策略类似于上面的状态,是一个对象。不同的策略对象里定义了不同的处理逻辑。使用不同的策略就是调用不同的策略对象里的处理逻辑。
备忘录模式是干任何一个原子化的操作时,都做一个记录。在React中,使用immutablejs就可以实现应用状态的录制与回放。
兄弟组件之间通过父组件相互之间进行交互,就是一种中介者模式。父组件可以定义子组件之间如何交互,相比子组件之间直接交互灵活性差一点,但是鲁棒性更高。
访问者模式非常有意思,你想要一个数据,你可以让对方告诉你,比如设置一个回调让对方调用,也可以直接去读取。简单说这种主动读取数据的模式就是访问者模式,读哪些数据,怎么读取这取决于访问者。轮询就是访问者模式,这使得数据提供者不需要主动推送数据给使用方,也不需要知道使用方需要什么数据。
模板方法模式底层逻辑就是人解决问题的思维方式:将一个处理过程分为多步并明确的定义出来。只不过模版方法是用来处理类似但不同对象的。有点像函数式编程的那种感觉。当然数据处理型的逻辑在前端开发中比较少,所以大家比较难体会。
桥接模式也前端同学也比较难理解。其实接口就是一个最本质的桥接模式。系统的各个模块直接通过接口相互连接在一起。至于接口如何实现,不影响系统相互直接的连接。比如nodejs可以运行在不同的操作系统环境中,肯定有一个桥接层,定义了node与操作系统如何交互。
构造器模式创建对象,不同于new 对象。对于具有复杂功能,复杂成员的对象,可以使用构造器,分步骤来初始化成员以及自身状态。每个步骤也支持传入参数来控制成员的构造情况。底层思维还是复杂问题分步解决。
工厂方法模式创建对象和new一个对象差异不是很大。只不过是类上定义了一个静态函数用来创建自己的一个实例。
抽象工厂方法模式则是放大了工厂方法模式。有一个类专门来负责创建对象。抽象类定义了要创建什么,而实现的工厂类则负责实现具体的创建逻辑。
未完待续……