论MVVM伪框架结构和MVC中M的落实机制。《论MVVM伪框架结构和MVC中M的兑现机制同M层的构建》阅读笔记。

目录

《论MVVM伪框架结构和MVC中M的实现机制以及M层的构建》阅读笔记
原文链接

  • MVC概论【本文】
  • 模型层设计艺术【请参考:http://www.jianshu.com/p/fce02188edec】
  • 控制层的规划方法【敬请期待】
* 业务类中的属性设计为只读。
* 数据模型类中的属性定义最好也设置为只读,因为数据模型的建立是在业务类方法内部完成并通过通知或者异步回调的方式交给使用者。而不应该交由使用者来创建和更新。
* 数据模型类一般提供一个带有所有属性的init初始化方法,而初始化后这些属性原则上是不能被再次改变,所以应该设置为只读属性。

一直都有人做吹捧MVVM应用开发框架,文章将MVVM说之好听并且批评包括iOS和android所用底MVC经典框架。这首稿子就是想叫那些捧臭脚的人们泼泼冷水,虽然发出或致骂声一片,但是目的是让那些刚入门的伴一些参阅和建议,以免误入歧途。同时为于那些深陷其中不能自拔的同伴等敲敲警钟,以免其在左的道及越走越远。

  1. 精之框架中各个层次之拆分并无是简简单单的拿代码进行归类和分,层次之分割是横向的,而模块的分是纵向的。
  2. 视图负责展示及渲染,模型负责作业逻辑的兑现,控制负责调度视图的轩然大波以及业务逻辑的调用以及通知视图的刷新通知。
  3. 免克拿M层简单明了啊平淡的只有属性没有办法的数据模型。
  4. M层是业务模型层而不数据模型层。
  5. 可观的施用与框架并无以代码的数目,而是完全系统的代码简单好读,各部分任务分明,容易保障和调剂。
  6. M层要形成对工作逻辑实现之包裹,一般工作逻辑最多的凡关系到客户端和服务器之间的作业交互。M层要就对运用网络协议和服务器之间的并行数据格式,本地缓存和数据库存储等有事情细节之卷入,这些事物不能够暴露于C层,只叫其提供一个接口
  7. C层的作用就是是处理视图的风波,然后调用业务逻辑,接收工作逻辑的处理结果通知,然后通知视图去刷新界面。
  8. M层是生产者,负责数据的构建和更新,C和V层负责数据的行使及花。
  9. C具有负责创建并有M层对象的事,C层也是一个动观察者。
  10. C层负责M层的艺术调用。
  11. C层负责观察M层的多少变动通知并展开相应处理。

—— MVVM并非框架,而只是略的文书夹分类 ——

view层的组织以及调用方案

MVVM被引入的前因后果

盖是在2010年左右运动端支出火了起来,起初是iOS,Android,
WinPhone三个老平台竞争,后来后人退出了战斗,变成了次分世界。从下体系布局以及为开发者提供的框架体系来拘禁,两只平台还是产了藏MVC三叠结构的开发方式,这三层所表示的义是范、视图、控制。这个开框架的初衷其实也特别粗略:视图负责展示以及渲染,模型负责作业逻辑的兑现,控制负责调度视图的波以及业务逻辑的调用以及通知视图的基础代谢通知。
三有松散耦合,各司其职。下面是藏的MVC框架结构:

[图形及传失败…(image-1d68cb-1512992093070)]

一个很心疼的真相是管是Android和iOS都只对C和V两部分进行了正式的概念和兑现:Android的视图部分的贯彻是概念了各种控件以及由此XML文件来组装视图布局界面,iOS的视图的兑现啊是概念了各种控件以及由此XIB或SB来组装视图布局界面;
Android的控制部分则是由此Activity来实现,而iOS的支配部分则是经过UIViewController来实现的。而模型有吗?因为每个应用的作业逻辑和采取场景并不相同,所以片单阳台吗束手无策为非克定义来一个通用的模型层出来,而是将模型层的定义留给了开发者来兑现。然而这也我们的开发者在运MVC框架开发使时盖下了隐患。

初的使开发相对简便易行,因为无专业的模型层的概念,而控制层又当工程变更时预留了诸多可是供应开发者写代码的地方,所以广大开发人员就自然而然的拿业务逻辑、网络要、数据库操作、报文拼装和剖析等等全部代码都放入了控制层里面去矣,根本就无欲什么模型层的概念。
这样就日的缓和采用之复杂性增加,就起了C层膨胀的动静了。一个控制器的代码可能出现了好几千推行的现象。于是乎有人便开搜索解决方案来吧C层瘦身了。又一个很可惜的真情是还并未丁去思在抽象出M层,而是用了之类方法来缓解问题:

  • 客户端和服务器之间交互的数报文是否好定义有一个个只有属性而尚未法的数额对象呢?这样以处理以及渲染界面时即便无欲和旧之XML或者JSON或者其他的格式报文交互了,只要操作数据对象就好了。于是解决方案就是是依据客户端和服务器之间交互报文定义来一个个底数据模型,然后还出出同拟XML或者JSON和数据模型之间互转的解析器来。最后将即刻一个个一味生数据如果并未办法的对象数据模型统一置于一个地方,然后让他俩定义为M模型层(呼!终于让闹模型层的定义了,但是:Are
    you kidding
    me??)
    。这样C层就非会见再次起XML或JSON解析和一直读取报文的代码了!而是把及时片代码挪至范层了(大家来拘禁呀,我竟下及了MVC框架了!)
    好了!瘦身第一步成功。但是可,问题还当什么,我的政工逻辑还是同大片在C层啊,看来MVC这种框架为可是这样啊!根本未曾解决本身的题材。不行,我非克还用MVC这种框架来支付自己之运用了,我一旦另找她套,要持续指向C层瘦身。

  • 我之某界面与有业务逻辑是绑定在相同块的,这个界面的示是经调用某个业务逻辑来落实之,业务逻辑完成后如果一直更新是界面。这种环环相扣的调用和创新关系从来就是未待C层的插手。因此可以以立刻片界面的翻新刷新以及工作逻辑的调用绑定在协同,
    二者结合也一个封闭而独立的一体化并形成独立的类似。这样把这类似的代码抽离出来了,存放到一个独自的文件夹着。我将这有些于什么好与否?对了就给视图模型层VM吧!视图模型层中之类定义了一个深受外部使用的唯一接口来供C层调用。这样我竟把同挺组成部分代码从C层中抽离出来了。我就打响的落实了C层的尤其瘦身,并抽象出了一个视图模型层了!(不过哪里好像不对,视图模型层设计及了视图、模型、视图模型层三上面的交互和耦合)
    不过没有关联,反正自己的C层进一步瘦身成功了!,我看还可免可以继承瘦身C层?

V和VM以及M之间的依靠关系

  • 自之好多视图的轩然大波是在C层中处理的,那我是未是可以管C层的事件处理也将出去也?
    干脆就是以出来吧。但是怎么将出去呢?于是乎我以休歇的寻找,终于找到一个叫RAC的物了,这个事物好哎,他得负担处理视图的各种风波,以及可当连续的大网调用。等等。。。
    RAC就是发出接触晦涩难理解!难以学习,代码难以阅读和调试。怎么收拾?
    没有提到,只要是能够以C层的代码瘦身这些以算什么。。。大莫了就是大抵次一点坑,多打几不行培训就好了。
    嗯! 就这样办,那自己拿当下有些代码也放入到VM层里面去吧。

    。。。。呼!!!
    C层终于瘦身成功。然后大家看什么,我之C层里面确实是什么代码也从没了。。。
    它不再处理视图的事件了,因为事件让RAC给处理了、它呢无处理视图的刷新以及业务逻辑的调用了因为被视图模型MV给处理掉了、他吧无处理数据的解析了以于范层为替换掉了。嗯。。。。我而给这种没有C层或者不待C层的框架起个名,叫什么好吗?
    就为:MVVM吧。。。
    我的利用得绝不C层了,然后我不怕奔走相告。将C层无用大白于天下。。

确实是这么呢?答案是NO!!!

首先自己想说之是一个优质之框架中列层次的拆分并无是大概的以代码进行归类和剪切,**层次的分开是横向的,而模块的划分则是纵向的
** 。
这里面涉及到了层次中的耦合性和任务的分开,以及层及层里的竞相接口定义和艺术,同时层内的统筹啊应该有惊人的内聚性和结构性。而这些计划的渴求并不曾以所谓的MVVM中体现出。

  • 率先使科学的了解MVC中的M是什么?他是数据模型吗?答案是NO。他的是定义是工作模型。也不怕是若具备事务数据以及工作实现逻辑都应该定义在M层里面,而且工作逻辑的兑现同定义应该与切实的界面无关,也就是是暨视图以及控制中没有外的涉嫌,它是足以独自存在的,您还可将业务模型单独编译出一个静态库来提供给第三方或者其它系统应用。在面经典MVC图中也不行鲜明的描述了马上一点:**
    控制负责调用模型,而模型则将处理结果发送通知于控制,控制再通知视图刷新。因此我们不可知以M简单的知啊一个个干燥的只有属性而并未辙的数据模型。其实这之中涉及到一个最中心的筹划基准,那就算是面向对象的骨干计划规范:就是什么是相仿?类应该是一个个享有同样操作与见仁见智属性之靶子的抽象。
    我眷恋今天别一个系里面都不曾出现过一样堆积只生数据而尚未办法的数据模型的集聚被定义也一个单独而空虚的型层来供大家使用吧。**
    我们无可知将一个保留数据模型的文本夹来作为一个交汇,这并无相符横向切分的条条框框。所以说MVVM里面的所谓对M层的定义就是是一个伪概念。

  • 方我早已证明M层是工作模型层而未数据模型层,业务模型层应该封装所有的作业逻辑的落实,并且和实际视图无关。我们无克用一个视图的表现逻辑绑死在一个事务处理逻辑之中,因为发或存在一个事情逻辑来多种不同的变现形式,也恐怕界面显示会趁机以升级而变,但是事情逻辑是相对平稳的。即使是某视图确实就是与这业务是密不可分耦合的,也未应举行强耦合绑定。所以地方所谓的VM这种用视图的来得与工作的拍卖逻辑绑定以同一块是格外不好的方,因为如此的宏图方既完全违背了系统间太核心的显得同实现该分别处理原则。而且这种计划之沉思是跟支行的理念是负的。因为他起了视图和工作的紧耦合和互动双向依赖问题,以及与所谓的M层也使紧耦合的是。所以说MVVM里面所谓的VM层的概念也是一个伪概念。所谓的VM层这里面只不过是仍页面进行的功效拆分而已,根本就是讲讲不达标所谓的重叠的定义。

  • 重新来说说事件处理。经典的C层设计之目的是肩负事件处理和调度,不论是按钮点击还是UITableview的delegate以及ListView的Adapter都极端好放在C层来拍卖,这也是顺应C层最实质之概念:就是C层是一个负担调度以及操纵的模块,它是V层和M层的粘合剂,他的意向就是处理视图的事件,然后调用业务逻辑,然后接收工作逻辑的处理结果通知,然后再次通报视图去刷新界面,这就算是C层存在的义。而且系统默认为是以此办法设计的。而RAC的面世则将立即片之拍卖为的的代掉了。也就是经RAC所谓的响应式和触发式这种机制就能够实现将事件之调度处理在另地方其他时候还能够不辱使命。这样做的目的使得我们好分散和说代码。但结果出现的问题吧?就是与一个单元调度处理逻辑与机能的构建完全在了一个地方,但不同之单元逻辑的还要散在不同之地方,无法去分类统一保管与护卫。因此你无法一下子就掌握某功能有所调度到底是什么样促成与在哪里实现的。因为RAC将力量构建与事件处理完全粘合到一个颇的函数体内部,并且是代码套代码的模式,这种办法严重的毁伤了面向对象里面的构建和拍卖分离之设计模式理论。更麻烦的凡那个高昂的上和保安资金,代码阅读理解困难,以及无处不在的闭包使用。试想一下斯对于一个新专家的话是免是噩梦?,一旦产生了问题对保护和代码调试是无是噩梦?而且使用不当就会产出循环引用的不得了问题。这样一来原本C层一个调度总管的天职被RAC来接管后,这些处理将移得分散和无序,当我们而开一些集合之管制仍HOOK和AOP方面的事物常常就是变换得力不从心下手了。
    不可否认的凡RAC在处理连续调用以及各个响应方面发生得的优势。一个例是咱们兴许发生连接的大半个跟服务器的大网要,这时候用RAC进行这种处理能便民之解决问题。但是我想说之是当在这种现象时,我们尤其应该用这种连接的纱调用在M层内部消化掉,而仅仅吃C层提供一个简便而便宜之接口,让C层向不欲关怀这种调用的连续性。因此可说为拿C层的代码给消化掉而引入RAC的建制,不仅没简化掉系统反而下跌了网的可维护性和可读性。RAC机制向就是非合乎用当事件处理中。良好之以和框架并无在代码的数,而是完全系统的代码简单容易读,各组成部分任务明确,容易保障的调试

—— MVVM被引入的根本原因是针对性M层的错误认识所招的 ——

M应该做的事:
给ViewController提供数据
给ViewController存储数据提供接口
提供经过抽象的业务基本组件,供Controller调度

C应该做的事:
管理View Container的生命周期
负责生成所有的View实例,并放入View Container
监听来自View与业务有关的事件,通过与Model的合作,来完成对应事件的业务。

V应该做的事:
响应与业务无关的事件,并因此引发动画效果,点击反馈(如果合适的话,尽量还是放在View去做)等。
界面元素表达

MVC中M层实现的律

说了那么基本上,可以总结出所谓的MVVM其实并无是均等种植所谓的框架或模式,他仅仅是一个不法框架而已,他只是以作用以及拍卖按文件夹的计展开了分,最终的的结果是系统乱成了一样锅粥。毫无层次可言,所拥有的唯一亮点是拿C层的代码和职能了弱化了。其实出现这种计划方极其根本之来头即没有指向M层进行不易的明定义及拆分。那么我们应该怎么对的来定义跟规划M层呢?下面是自我个人觉得的几单准则(也许与其他人的眼光来出入):

  • 概念的M层中之代码应该跟V层和C层完全无关的,也便是M层的目标是不欲依靠任何C层和V层的对象要单独在的。整个框架的统筹极端理想布局是V层不依赖C层而单身存在,M层不依赖C层和V层独立在,C层负责涉二哟,V层只担负展示,M层持有数量与事务的切切实实贯彻,而C层则处理事件响应与业务的调用以及通知界面更新。三者之间自然要显著的定义为才为据,而未应出现双向依赖。下面是三重叠的靠关系图:

老三层之间的特为依靠关系

除非当你系统规划的不同部分都是光为依靠时,才可能好之进展层次拆分和每个层的效能独立替换。

  • M层要做到对作业逻辑实现之包装,一般工作逻辑最多之是关乎到客户端和服务器之间的事务交互。M层里面要到位对下的网络协议(HTTP,
    TCP,其他)、和服务器之间交互的数据格式(XML,
    JSON,其他)、本地缓存和数据库存储(COREDATA,
    SQLITE,其他)等具备事务细节之卷入,而且这些东西还不能够暴露被C层。所有供C层调用的且是M层里面一个个事务类似所提供的分子方法来实现。也就是说C层是无需掌握吗无该明了和客户端与服务器通信所祭的别样协议,以及数报文格式,以及存储方的情。这样的利益是客户端和服务器之间的通信协议,数据格式,以及地方存储的变动都不见面潜移默化外的用整体框架,因为提供给C层的接口不换,只需要升级以及更新M层的代码就足以了。比如说我们想将网络要求库从ASI换成AFN就如在M层变化就得了,整个C层和V层的代码不移。下面是M层内部层次的定义图:

M层内部的包装层次

  • 既是我们的用是一个完好而还要分开模块,那么业务层内部也相应遵循功能模块进行结构划分,而未应有简单且平面的照同服务器之间通信的接口来展开工作层次的平面封装。我信任有诸多人口犹是对M层的卷入就是简单的照与服务器之间的相接口来概括的包。下面的星星点点种不同之M层实现之政工封装方式:

零星栽不同之M层封装实现

咱还得更进一步的指向工作逻辑抽象出M层的接口及贯彻两部分,这样的一个功利是相同之接口可以有异之兑现方式,以及M层可以隐藏非常多的中数据与方要休露于调用者知道。通过接口及兑现分离我们尚好以未改变原先实现之根底及,重新重构业务有的兑现,同时这种模式吗深轻MOCK一个测试实现,这样在展开调节时方可充分粗略的在实实现与MOCK实现中切换,而毋庸每次都同劳务器端进行互调试,从而实现客户端和服务器之间的分别支付及调节。下面是一个升任版本的M层体系布局:

因接口的M层实现

  • M层如何和C层交互的题目也急需考虑,因为M层是无需懂得C层和V层的是的,那么M层在作业处理完后什么错过通知C层呢?方法发生好多种:
    • 俺们好为M层的通逻辑定义Delegate协议,然后给C层去贯彻这些协议,然后M层提供一个delegate属性来赋值处理事务通知之靶子。
    • 咱吧得定义众多之NSNotification或者波总线,然后当M层的事情处理完毕后可发送通知,并且以C层实现通之处理逻辑。
    • 咱们得为此闭包回调或者接口匿名实现目标的形式来贯彻业务逻辑完成的关照功能。而且好定义有专业:所有M层对象的方的末梢一个参数还是一个正规的如下格式的block或者接口回调:

typedef void (^UICallback)(id obj, NSError * error);

这种模式其实当群系统中有利用至。大家可参数考苹果的CoreLocation.framework中之地理位置反解析的类CLGeocoder的概念。还有一些之是于AFN以及ASI中之大网要部分还是将成功和破产的处理分成了2单block回调,但是此间建议以吃C层的异步通知回调里面未分2独block来调用,而是一个block用2单参数来解决。因为来或我们的处理面临管成或者失败且可能产生有代码是一般之,如果分别则会出现又代码的题材。

delegate这种模式并无囿于为M和C之间,同样也可使用在V和C之间。

delegate本质实际上是平栽双方间通信的接口,而经过接口来开展通信则好极其充分限度的减对象期间的耦合。

MVC中M层实现之简易举例

末尾咱们因为一个粗略的用户体系的报到系统来贯彻一个M层。

1.定义标准的M层异步回调接口:

//定义标准的C层回调block。这里面的obj会根据不同对象的方法的返回而有差异。
typedef void (^UICallback)(id obj, NSError * error);

//这里定义标准的数据解析block,这个block供M层内部解析用,不对外暴露
typedef id (^DataParse)(id retData, NSError * error);

2.概念有M层业务类的基类,这样在通用基类里面我们好开过多甩卖。比如网络层的汇合调用,加解密,压缩解压缩,我们还得做AOP和HOOK方面的拍卖。

     @interface  ModelBase

           //定义一个停止请求的方法
           -(void) stopRequest;
           /**
             *定义一个网络请求的唯一入口方法
             * url 请求的URL
             * inParam: 入参
             * outParse: 返回数据解析block,由派生类实现
             * callback: C层通知block
             */
           -(void) startRequest:(NSString*)url  inParam:(id)inParam outParse:(DataParse)outParse  callback:(UICallback)callback;
     @end

3.概念一个用户类:

    @interface  ModelUser:ModelBase

        @property(readonly) BOOL isLogin;
        @property(readonly) NSString *name;

       //定义登录方法,注意这个登录方法的实现内部可能会连续做N个网络请求,但是我们要求都在login方法内部处理,而不暴露给C层。
       -(void)login:(NSString*)name  password:(NSString*)password   callback:(UICallback)callback;
        //定义退出登录方法
       -(void)logout:(UICallback)callback;
    @end

4.定义一个M层总体系统类(可选),这个仿佛可是单例对象:

    @interface ModelSystem:ModelBase

     +(ModelSystem*)sharedInstance;

    //聚合用户对象,注意这里是readonly的,也就是C层是不能直接修改用户对象,这样保证了安全,也表明了C层对用户对象的使用权限。
    @property(readonly)  ModelUser *user;  

    //定义其他聚合的模块

    @end

5.以C层调用用户登录:

  @implementation LoginViewController

    -(IBAction)handleLogin:(UIButton*)sender
   {
        sender.userInteractionEnabled = NO;
        __weak LoginViewController  *weakSelf = self;
       [[ModelSystem sharedInstance].user  login:@"aaa" password:@"bbb"  callback:^(ModelUser *user, NSError *error){

        if (weakSelf == nil)
               return;
       sender.userInteractionEnabled = YES;
       if (error == nil)
       {
              //登录成功,页面跳转
       }
       else
      {
            //显示error的错误信息。。
      }}];

   }

   @end

足见见地方的C层的一部分非常简单明了,代码也易读和爱了解。同时我们尚见到了C层跟本不需明白M层的记名实现到底是什么样告网络的,以及要了几独大网操作,以及用之哎协议,以及什么数据报文格式,所有的及时一体还封闭装于了M层内部贯彻了。C层所假设举行的虽是粗略的调用M层所提供的方,然后以callback中通界面更新即可。整个C层的逻辑吗不怕是几十尽就是会闹定矣。

实际的模型层设计艺术要参见:M层的统筹


欢迎大家关心自身的github地址,关注欧阳大哥2013,关注自我之简书地址:http://www.jianshu.com/u/3c9287519f58

除开delegate外也可使用Block异步通知方式

typedef void (^BlockHandler)(id obj, NSError *error);

动用block方式定义异步方法时一般只要符合如下几个规则:

  1. BlockHandler的参数确保就是原则性的2只:一个是异步方法返回的对象,这个目标足以依据不同之方式而归不同的对象。一个NSError目标表示异步访问有了错的归。
  2. block回调拍卖作为艺术的尾声一个葡京会参数。
  3. 匪建议在一个法被冒出零星只block回调:一个不利的和一个垮的。
  4. 引进:对于以M层对象中
    某个请求通过block回调来打招呼调用者进行异步更新的体制。一个条件,只要涉及到M层对象的主意调用都尽量走正规block回调这种办法。例如:

- (void)fn1:(参数类型)参数 callback:(BlockHandler)callback;
- (void)fn2:(参数类型)参数 callback:(BlockHandler)callback;
- (void)fn4:(参数类型)参数 callback:(BlockHandler)callback;
- (void)fn5:(参数类型)参数 callback:(BlockHandler)callback;

点的道实现同调用机制看起都怪统一而是规范。即使有方法并无外异步动作,也太好遵守这种模式,因为某天有或会见从同实现成为异步实现。这样的话只待转C层的代码即可。

delegate异步通知和Block异步通知的选择参考:

  • 使某类中具备许多单艺术,而每个方法以实现了不同的效益,并且方法的异步返回数据以及这个方法有十分强的关联性就应当考虑动用block而不是delegate
  • 设若类似中之法子的异步方法是那种一差相就收获一个差的结果,而且得的结果以及上次结果没什么关联,就考虑用block而不是delegate
  • 若是我们调整用类似中的某个方法,而调用前设置了部分上下文,而调用方法后我们而望根据是上下文来处理的回结果经常,就考虑以block而不是delegate
  • 而我们调用类里面的某方法,而回到的结果莫需要与上下文进行关联那么就是考虑动用Delegate而不用block
  • 一经只要实时的观赛业务类里面的某个属性之扭转时,我们就算该考虑采取Delegate如果休是应用block
  • 假若业务类里面的异步通知或者分为好几只步骤那即使考虑用Delegate假如未是行使block

嗬状况下用KVO的方法贯彻异步通知回调:

  1. 有对象的同数据更新可能会见挑起多只因之目标的靶子的创新变更处理。
  2. 若某对象的生命周期要比较观察者短则免建议用KVO的计,因为是来或会见导致系统的倒台而致使巨大的影响。

delegate和block的缺点

  • delegate的方法要使先期定义来一个接口协议来,并且调用者和实现者都亟需以这个接口规则来拓展通报及数量处理相互,这样平空就闹了必然之耦合性,也就算是二者之间还是具有隐式的凭。不便宜扩展和拓展完全从定义处理。
  • block的缺点:
    1. 凡用不好会产生循环引用的题材
    2. 差后难以调试和难以展开问题追踪
    3. 代码中发生多重新嵌套,从而影响代码的菲菲及可读性

KVO机制的优点

业务对象和观察者之间完全脱离了耦合性,而且数量变化后底打招呼了是因为网来拍卖,不需要丰富附加的代码和逻辑,而且好实现多观察者而监听一客数据。

缺点:只能对性之变型进行察看。

NSNotification缺点

这种机制过于松散,没有关系的上下文。给使用者带来了定的攻成本。

总结

当统筹一个业务层时,首先应要是本着事情拓展精心的分析和透亮,然后构建出一个近乎组织图,这种静态框架设计好下,就得对类进行角色跟任务分开,哪些应该设计为多少模型类,哪些该设计也罢业务类。

admin

网站地图xml地图