iOS程序设计心得总结(三)应用层设计

来源:互联网 发布:唯一网络王宇杰简介 编辑:程序博客网 时间:2024/05/01 01:12

应用层设计

几种常见架构模式的简单认识 

 应用层负责界面交互与业务串联,这个层次涉及的东西就比较多变了,在设计架构上也最考验功力,大家喜闻乐见的MVC、MVP、MVVM等等这些架构模式也都是在这一层次的应用。首先,先大概总结一下自己对这几种常见模式的简单认识。

mvc:(网上找的图)

   

  mvc大概流程是这样的,view负责接收用户输入交给controller,然后controller根据不同的交互执行不同的逻辑,对数据(model)进行相应操作,操作完成后(model改变),controller进行view的刷新,view根据最新的model状态做新的界面展示,反馈给用户.
 优点:理论简单,易于理解,易于实现,缺点:1.view与model有耦合 2.controller负担过重,臃肿。

mvp:(网上找的图)

mvp对mvc进行了一些改进,view与model之间的连线没有了,也就是说这种模式相较mvc,做到了view与model之间的结耦,但依然存在Presenter(Controller)过重的问题。

mvvm:(网上找的图)


mvvm对mvp模式进行了近一步改进,上面说了mvp做到了view与model之间的结耦,但依然存在Presenter(Controller)过重的问题.mvvm中首先view与model同样也是结耦的,但相较mvp,引入vm层带来了以下好处:1.在vm层中加入对数据的加工、校验等处理,使view更专注于ui展现层面上的工作;2.借助vm层,view与model间建立起了沟通机制(通过通知、kvo等手段),解放了presenter中同步view与model状态的这部分工作,缓解了Presenter(Controller)过重的问题。

所以它们之间是一个渐进优化的过程,mvc(mv耦合、c过重)->mvp(mv解耦合,c过重)->mvp(mv解耦合,v更纯粹、c负担减轻)

在项目中对架构模式的应用

  下面总结一下我对这些模式是如何使用的,及它们在项目中的使用场景(同一个项目中,不同的需求,采用不同的设计模式)。

mvc模式使用  

回顾一下之前总结的mvc,流程上,view负责接收用户输入交给controller,然后controller根据不同的交互执行不同的逻辑,对数据(model)进行相应操作,操作完成后(model改变),controller进行view的刷新,view根据最新的model状态做新的界面展示,反馈给用户. 绝大部分情况下我会按常规mvc的模式进行开发,类似代码如下
//model@interface PersonModel : NSObject@property (nonatomic,copy) NSString *name;@property (nonatomic,copy) NSString *photoName;@end
//view@interface PersonView (){    UILabel *_nameLabel;    UIImageView *_headImg;    //维持一个model    PersonModel *_person;}@end
//PersonView.m-(void)setPerson:(PersonModel *)person{    //绑定model    _person = person;    //同时每次重新绑定(数据变化)时,ui随之刷新    _nameLabel.text = _person.name;    _headImg.image = [UIImage imageNamed:_person.photoName];}
controller中,每当person数据产生变化,都会调用[personView setPerson:person],进行view中model的更新(重新绑定view与model),同时view界面随之刷新。
上面这种开发方式简单、直观,但是有些小问题,比如仅仅是person的name产生了变化,为了界面能够得到刷新,仍然需要重新调用personView的setPerson方法,重新为view绑定一下person,即便发生改变的仅仅是个别属性.这样做倒是不会出现什么问题,但是确实显得不是太合理。如果看不过去,我们可以让view单独提供一个refresh方法,供viewcontroller去使用,setPerson仅仅做纯粹的模型绑定
-(void)refresh{    _nameLabel.text = _person.name;    _headImg.image = [UIImage imageNamed:_person.photoName];}
这样,当viewcontroller中person数据仅仅是某个或某些属性变化时,我们就不必去重新做view模型的重新绑定,而是只要调用refresh方法即可做到界面的刷新,在逻辑上变显的更为合理一些。

简化mvvm模式的使用

  上面这种普通的mvc开发形式大部分情况下能很好的满足我的开发需求,但是它存在这样的问题,就是如果一个controller中管理的模型属性很多,而且每个属性都比较善变的话,我就需要在每个属性产生变化的点(时机),让controller去做view刷新的逻辑处理(通过重新给view绑定模型亦或是调用refresh方法),在这种情况下,维护成本、代码的出错几率以及controller的负担都会大大增加,于是,在个别情况下,我会采取下面这种开发方式,缓解这种问题的发生,类似代码如下:
-(void)setPerson:(PersonModel *)person{    if (_person != person)    {        [_person removeObserver:self forKeyPath:@"name"];        [_person removeObserver:self forKeyPath:@"photoName"];                _person = person;        _nameLabel.text = _person.name;        _headImg.image = [UIImage imageNamed:_person.photoName];                [_person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];        [_person addObserver:self forKeyPath:@"photoName" options:NSKeyValueObservingOptionNew context:nil];    }}- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {    if ([keyPath isEqualToString:@"name"])    {        _nameLabel.text = _person.name;    }    else if ([keyPath isEqualToString:@"photoName"])    {        _headImg.image = [UIImage imageNamed:_person.photoName];    }}
通过kvo等类似机制,建立其view与model间的通道,这样当模型属性产生变化时,view可以自动得到刷新,省去了controller之前所做的协调工作。这个形式很像mvvm,但是因为m与v并没有做到解耦,少了vm这一层,所以只能算是mvc的改进或是简化版本的mvvm,之所以不彻底以mvvm形式去实现,主要还是为了节省vm层的开发工作,同时尽量减少过多的中间层次,方便开发与调试。

mvp模式使用

  在每个项目中基本上都会有一些界面的ui样式是十分接近或类似的,为了避免对这些界面(view)的重复开发,这时我会用到mvp的设计方式,让m与v解耦,使view更纯粹,具有可复用性,一处开发,多处使用。类似代码如下:
@interface UIViewForStyle1 (){    UILabel *_label;    UIImageView *_imgView;}@end
-(void)setText:(NSString *)text imgName:(NSString *)imagName{    _label.text = text;    _imgView.image = [UIImage imageNamed:imagName];}
PersonModel *person = [[PersonModel alloc] init];person.name = @"zc";person.photoName = @"head";[_view setText:person.name imgName:person.photoName];    BookModel *book = [[BookModel alloc] init];book.name = @"iOS开发";book.cover = @"cover";[_view setText:book.name imgName:book.cover];
  在mvp模式下,与mvc的主要区别就是不要让view与model产生绑定,view层在显示的时候,不要去关心具体我显示内容的逻辑(业务)含义,显示的是书名+封面也好,是人名+头像也好,也可能是地名+地图,都可以,对于view来说就是一段文字+一个图片,这样,这个view就可以抛开业务,用到各个需要的地方,减少ui(view)层的开发工作。

mvc使用中的模块细分

  回过头来再去说说关于mvc的使用。个人认为,mvc模式其实存在最大的问题还是controller负担过重(过于臃肿),在mvc模式下,想让一个controller中包含成百上千(甚至几千)行代码是很容易就能做到的,这样造成的后果就是,各种业务逻辑都揉杂在了一起,十分容易产生错误,而且越到后面越是难以维护,所以mvc可以使用,但是一定要通过设计,尽可能的减轻controller的压力,解决controller的臃肿问题。
  首先,通过前面我们在数据层(点击打开链接)和网络层(点击打开链接)中进行的设计实现工作,其实已经将针对每个业务的具体逻辑实现转移到了下层,理论上上层仅仅剩下了界面交互响应和业务串联的工作,这样就先分担走了controller的一大部分任务。
  但是,现在的app大都界面复杂,上层逻辑转接方式也是形式多样,controller仍然会面临着相当大的压力。举个例子,就在今天我写这篇文章时,还在论坛上看到了有人又问了这样的问题"一个controller里添加了两个table产生了错误,如何处理?"底下还是有很多人回复,"通过tag去做table的判断云云... ",却没有一个人从设计的角度上帮他去分析、解决这个问题。抛开它这个问题不说,我敢说它这个controller里代码量肯定不少,里面承载的逻辑估计也是够多的。为什么会造成这个问题呢?我觉得主要还是太过教条的遵循着mvc的模式规范,不够变通造成的。mvc不一定就只能有一个c(controller);在iOS开发中这个c也不一定就一定要是controller。分开来说,

mvc不一定就只能有一个c (controller)

  就拿上面那个朋友提的问题来说,一个页面里有两个tableview,那这两个tableview的相关逻辑就一定要都交给这一个controller去承担吗?如果他能把着两个tableview相关的数据源、代理方法、对应的业务等都拆分出来,分别在两个不同的view中去处理(各自的处理,各自封装到不同的view中),每个子view都各管一摊,剩下原来那个主controller只要负责两个tableview间的协调配合、整体布局这些更高层面的管理工作就可以了,不用去关心两个tableview各自的具体细节,我相信,这样改造后它的这个controller就没那么大,那么乱了,他现在纠结的问题同样也不会发生了(分别各自处理自己的业务,不再都集中到一个controller里处理,也就不存在区分tableview、tableview逻辑相互冲突等困扰了).其实类似的情况,每个项目中都会遇到很多,我想说的是,一个controller中承载的复杂的逻辑我们都是可以通过梳理、细分、归纳,将这些逻辑拆分成不同的子模块,在不同的viewcontroller(view)中各自实现的,最终再由主controller负责各个子controller(view)的协调、串联工作就可以了,让职责划分更为明确,负担更为分散,避免将所有压力都压在一个controller中,原来那个controller俨然从一个又当保姆、又当司机、又当厨子的身兼多职的多面手,升级成为了从容、优雅的大管家。

iOS中c不一定就要用controller

  刚开始做iOS开发时,我总是在纠结何时应创建一个controller,何时应去创建一个view?.其实,view和controller大部分情况下是一样的,在mvc设计层面上没有区别,都可以充当控制器的角色。view虽然看名字仅仅叫视图,但实际上业务逻辑处理、事件响应等等所有控制层面上的事情它也是完全可以承载的,比如一个tableview,我可以把它加在一个controller上,由controller去获取(刷新、绑定)数据源、完成tableview的各种代理方法,同样我也可以把相应的所有实现都封装到一个view中,二者是没有任何区别的。controller相较于view,无非就是多了屏幕旋转、appear、disappear这些时机回调、导航跳转等等一些更高层面的支持,大部分情况下在不用这些特性,或者在做上一段落中提到的,作为子模块分担主控制器压力时,完全没有必要非要去使用controller(controller比view更重一些,非必要时,使用view即可).

总结

  别的各种各样的设计模式还有很多,比如CDD、Router等等,这些东西我也会去看、去学习,但实际中去实践的机会还是很少的,主要是去领会、学习思想,实践层面还是务实一些好。结合具体的实际情况,不刻板、教条式的遵循设计框架、不盲目追求设计,过度设计,选择适合的才是最重要的。

  三篇文章写完了,都是自己一些浅显的认识总结,希望日后能继续不断提高。

0 0
原创粉丝点击