关于MVC的文章,有点价值 https://zhuanlan.zhihu.com/p/58585650
架构设计要点,是透传MVC架构的思维起点 https://zhuanlan.zhihu.com/p/73060146
(该架构已经在局部模块取得了成功,之前所有文章中外对于MVC的论述,个人认为都是含糊不清的,本文清新论述了MVC,同时更重要的是对其做了很大的完善,希望回到你的点评,改正错误,填补不足,共同进步)
模块化降低复杂性,组合或聚合提高复用度。组合水平分件越多、纵向层次越深,复用程度越高、系统复杂性越高。同时内部模块到最顶层模块的事件传递的复杂性也随之骤然上升。多度组合的边际效应,会消除复用优势。 事件从低层模块向高层模块传递有两种可能的原因,1)因系统设计引入的复杂性,这是事件传递是机械的。2)系统自身的需要,低层模块已经跨越机械性,复杂如此已经具有独立的概念,这时事件传递便是合理的。
软件的可扩展性、可维护性,对于机械性的模块划分和概念性的模块划分,都是艰巨的挑战。 本文首先论述机械性模块划分中的透传MVC架构,之后介绍透传MVC架构在概念性模块划分中的应用。
概念说明
下面是对几个要使用的概念的说明:
复合模块,一个上层模块对应n个下层模块,n的数量是在运行时由后端数据决定的。如iOS中的表视图和集合视图,都是复合视图。
视图,即表象,不要把它局限在用眼可以看到的花花绿绿。
模型,即实体,根据它视图将作出可复线的表示。
(下面这几张图需要再修正一下,大家先将就着看一下,取其意忘其形即可!)
MVC架构

控制层拉取数据、创建模型、绑定到视图。没有交互、没有模型状态改变,只是单纯的读取数据、显示数据。模型与视图不需要绑定。

模型层的状态变更,需要通过控制层确定的机制,在视图层上作出相应的反馈。视图层捕获的系统事件,可以通过控制器层确定的机制,作用于模型层。比如MVC系架构中的MVVM,把模型层以在特定粒度层次上绑定到视图层;同时把视图层的事件,以委托方式通过控制层传递到业务层的各个组件中去。
⚠️如何理解“通过控制层确定的机制”?

在图2)中一个视图层,通过控制层,与一个模型层关联。在这里视图本身是复合的,对应模型也是复合的,上层视图与模型直接通过控制层进行关联,但对于低层视图与模型如果把关联性都通过控制层建立不是正确的做法。视图的层次性,要求模型层对应的层次性。视图模型对应上层视图模型,复用模型对应低层视图模型。但这种设计需要并不是系统或是概念本身的内在要求,它是人类和与之发明的计算机技术因为能力不足,面对局部间具有相似结构的问题时而采用的策略,其目的仅仅在于效率的提高。这就好比存在度偏低的人类,在面对强大的动物或石头时,要借助适当的策略和工具是一样的道理。
层次与组合策略在复用上是十分成功。但是,低层模块在上层中的复用,并没有消除其直接与其它层次模块直接通信需求,如3)中的复用模型CM和视图模型VM,都需要直接和控制层直接通信。在层次与组合加持下,目前大多系统的低层模块都是通过委托与其它层次的模块进行通信!不难发现系统为此而引入的多种委托层次关系,当低层次模块与其它层次模块的通信需要加强、减弱或是修改时,需要需改一个委托链上的所有涉及的节点。
为了降低复杂度与提高复用性而引入的层次与组合策略,严重损害了系统的可维护性,再加上频繁的需求变动,其收益进一步降低。下面我们一起看看透传MVC架构是如何,在利用层次与组合策略带来的优势的同时,解决这个问题的!
透传MVC架构

层次与组合在复用性的提高上十分成功,其引入的低模块与其它层次的通信问题亦令人十分地懊恼。透传就是要在复用的低层模块与其它层次模块间开辟一条直接通信的通道,使其像本层次的最顶层模块一样,能够直接地对外通信。图4)是iOS中使用Objective-C的一种实现方式,通过类别向控制层添加低层模块到其的通信通道(透传协议),可以通过该通道以委托的方式实现,或是如上图一样直接把低层模块直接暴露给控制层,让控制层自行注册回调。
单层透传MVC架构适用于具有三个层次的视图(即表视图、单元视图、和单元内部的视图),下面是具有四个层次的透传MVC架构,双层透传MVC架构。

委托透取VS模块透传
在透传架构中,低层模块到其它层次的通信方式有两种,委托透取和模块透传。
所谓委托透取,即是低层模块,即委托者,通过透传协议,向其它层次主动获取委托对象的过程。其好处是明晰,在定义大的架构、具有复杂的业务场景或接口比较复杂时可以使用,但是代码量大,违背开闭原则。
⚠️为什么说委托透取违背开闭原则?
模块透传,我们是取其直观意义进行的命名,即透传协议直接把低层模块暴露给其它层次,如控制层。低层模块对外暴露自身的行为插槽,由其它层次主动向其注册响应函数,低层模块直接调用注册的响应函数。
委托透取和模块透传,到通信目标层次的通信都实现了通信的零转发,把控制强制交由控制层,这对模块的需改、模块的添加与删除,都是非常友好的设计:只需要找到控制层,把由其构建的关联解决掉即可!
机械性透传VS概念性透传
在自然界和人类社会中,单体趋向于机械性,而群体则更多地表现出智慧的特征,从蚂蚁、蜜蜂到人类社会都是这样。在系统设计中,这个事实同样存在!
对于架构,只要足够 “小” ,再复杂也是…www.zhihu.com低层模块对上层模块会显示出其机械性的一面,尤其是大量存在的低层模块,数量越大对上层模块展现的机械性越强。反之显示的概念性,即与其它层次交互性越强。
对于低层大量存在的模块,一般采用机械性透传,即把其行为全部交给其它层次或是层次中某个高层次模块来处理。
复杂的模块或是包含大量低层次模块的集合模块,它们足够大、足够复杂,对外表现出多个低层模块简单累加所没有的特性,这样的模块我们称之为概念性模块。如高层模块中存在概念性模块,这时系统构建会比较复杂,低层模块可能同时需要向,其它的层次与该层内的高层的概念性模块进行透传。
无论是概念性透传还是机械性透传,其解决的矛盾都是,模块化与组合引起的不必要的复杂事件传递与模块本质上一体化之间的矛盾,即分而治之的方法论对系统的有机性的割裂的矛盾。
透传架构的意义
系统的整体特性大于机械的各个模块特性之和,分而治之降低复杂性、提高复用度,是以提高了向高层模块与其它层次模块通信的成本为代价。透传,通过明确的协议定义,能够大幅度地降低层次模块的通信成本。
模型提供在业务逻辑控制下的数据,通过控制器,给到视图层使用。
UITableView 通过委托与数据源,为用户使用表视图的通道。但是这种设计在MVC架构下是狠糟糕的,面对交互的复杂的展现,会引起两种结果:
1)在纵向上引入多层委托,在横向上采用多个委托的组合;2)臃肿的控制器。
一方面,交互的内在需求,需要把尽可能多个委托和数据源方法在控制器中实现。如点击事件、滚动事件、移动事件等。令一方面,数据配置的复杂性又期望分离委托和数据源方法到其他对象中,提高模块化。但cell具有交互与数据配置的双重属性,这种撕裂是 UITableView 设计上失败的一个根本原因。可以说项目中99%臃肿的控制器、层层叠叠复杂的交互,都是这种设计缺陷引起的。
事件传递的复杂性我们通过透传架构来解决;
数据配置的复杂性,我们通过对 UITableView 的二次封装来解决。