内容简介:一般来说,MVP架构在Andriod中用的比较多,但它也可以在iOS中使用。我在重构项目的一个功能时,为了改善以前代码的层次结构,同时也想体验一下MVP的实践,所以使用了该模式,同时也积累了一点小技巧。MVP分层模型以及交互关系如图所示:view和model通过presenter进行交互,切断直接联系。
一般来说,MVP架构在Andriod中用的比较多,但它也可以在iOS中使用。我在重构项目的一个功能时,为了改善以前代码的层次结构,同时也想体验一下MVP的实践,所以使用了该模式,同时也积累了一点小技巧。
MVP分层模型以及交互关系如图所示:
view和model通过presenter进行交互,切断直接联系。
在使用该架构后,虽然分层清晰了,但是它有个缺点, presenter中粘合接口过多
。
我们知道,mvp各层的交互都是通过接口来完成的,presenter作为中介者,需要实现 view操作model层的接口
, model层操作UI的接口
。而presenter实现这些接口时,大部分是 简单的调用model和view的接口,并没有其他额外操作
,这样会导致presenter中粘合方法过多,并且新增接口,presenter也需要新增实现。所以,当功能复杂时,接口暴增,presenter中也会有越来越多的接口实现,同时也不利于维护。
先看个简单的弹幕例子,介绍下上面所说的问题。
Interface
// presenter提供的给view调用的接口 @protocol DanmuPresenterInterface <NSObject> @optional /// 清除聊天记录 - (void)cleanChats; @end 复制代码
// view提供的给presenter调用的接口 @protocol DanmuViewInterface <NSObject> @optional // reload - (void)reloadTableView; @end 复制代码
// model层调用presenter,更新ui接口 @protocol DanmuDataOutputInterface <NSObject> @optional // reload - (void)reloadTableView; @end 复制代码
// prenseter调用model层,更新数据接口 @protocol DanmuDataInterface <NSObject> @optional /// 清除聊天记录 - (void)cleanChats; @end 复制代码
Presenter
@interface DanmuPresenter() // 数据层接口 @property (nonatomic, strong) id<DanmuDataInterface> dataManager; // ui层接口 @property (nonatomic, weak) id<DanmuViewInterface> danmuViewInterface; @end @implementation DanmuPresenter // presenter提供的给view调用的接口 #pragma mark - DanmuPresenterInterface /// 清除聊天记录 - (void)cleanChats { [self.dataManager cleanChats]; } // 实现model层调用更新ui接口 #pragma mark - DanmuDataOutputInterface // reload - (void)reloadTableView { [self.danmuViewInterface reloadTableView]; } @end 复制代码
这个例子中,交互关系如下:
在view中的调用如下:
// self.presenterInterface为presenter [self.presenterInterface cleanChats]; 复制代码
在dataManager中调用如下:
// self.DanmuDataOutputInterface为presenter [self.DanmuDataOutputInterface reloadTableView]; 复制代码
从上面可以看出,如果 DanmuPresenterInterface、DanmuDataOutputInterface
有新增接口, presenter
中必须新增相应实现,比较麻烦。
实际上,在 danmuView
中调用 cleanChats
时, presenter
只是起了一层中转的作用,内部还是直接调用的 dataManager
的接口。对于这种类型的接口来说,会极大的增加 presenter
的接口实现方法数。
所以,在重构过程中,为了减少粘合接口,考虑直接将 消息转发到对应的实例
中,不需要写实现方法。如下所示。
- 如果是
danmuView
通过DanmuPresenterInterface
接口(最后实际上是调用DanmuDataInterface操作model数据
),则直接转发到dataManager
。 - 如果是
dataManager
调用DanmuDataOutputInterface
接口来更新UI,则直接转发到danmuView
。
// 由于presenter作为中介者,需要实现view操作model层的接口(具体实现为dataManger),model层操作UI的接口(具体实现为chatView),这样会导致粘合方法过多,并且新增接口,presenter也需要新增实现。故使用消息转发来简化处理。 - (id)forwardingTargetForSelector:(SEL)aSelector { // 转发DanmuDataInterface实现到dataManager struct objc_method_description omd = protocol_getMethodDescription(@protocol(DanmuDataInterface), aSelector, NO, YES); if (omd.name != NULL) { if ([self.dataManager respondsToSelector:aSelector]) { return self.dataManager; } } // 转发DanmuDataOutputInterface实现到danmuView omd = protocol_getMethodDescription(@protocol(DanmuDataOutputInterface), aSelector, NO, YES); if (omd.name != NULL) { if ([self.danmuViewInterface respondsToSelector:aSelector]) { return self.danmuViewInterface; } } return [super forwardingTargetForSelector:aSelector]; } 复制代码
这样, DanmuDataInterface、DanmuDataOutputInterface
中的接口在 presenter
中的实现均可去除。在 dataManager
调用的地方为 [self.uiInterface reloadTableView]
,注意这里不能判断 respondsToSelector
,因为 presenter
并没有实现这些方法,所以判断了不会走。
但是,这种做法是有限制的。要求presenter中实现的接口,是没有做任何额外的逻辑,而是直接调用model层或者ui层的实现。
比如,下面的实现另外调用了 [self xx]
,就不适用了。
#pragma mark - DanmuPresenterInterface /// 清除聊天记录 - (void)cleanChats { // do something [self xx]; [self.dataManager cleanChats]; } 复制代码
以上,就是mvp实践过程的小结。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 基于 CSE 的微服务架构实践:基础架构
- 典型数据库架构设计与实践 | 架构师之路
- 『互联网架构』软件架构-rocketmq之实践(62)
- HBase实践 | 数据人看Feed流-架构实践
- 架构实践全景图
- 微服务架构最佳实践
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。