笔者在前文 《MVP和MVC》中提到了两者的区别,以及MVP日趋流行的原因:即随着各种给力UI框架的发布,View的功能越来越强,已经足以完成一些简单的不需要与后台或其他view交互的event handling工作。
一位.NET工程师在他的博客写了MVP的14条规则,个人感觉十分靠谱,所以转载过来,并稍注翻译。
14条具体规则之前,他提到了一些MVP设计的基本共识,比如View必须实现Display接口,Display接口定义了View里面与Presenter交互的所有方法,通过Display的存在,View和Presenter得到完美的解耦,使得架构变得清晰,也为Presenter代码的测试带来极大的便利。View永远不直接调用任何其他模块或者服务,只专注于本身UI细节的实现,以及简单的不涉及与其他模块或服务交互的event处理。如果View需要Presenter提供数据或服务,则必须使用event。
1. All views should have a XxxView suffix: TaskView/ITaskView
2. All presenters should have a XxxPresenter suffix: TaskViewPresenter
3. Let the presenter do all use-case processing, but keep GUI control details in the view
让presenter处理所有的逻辑,把所有GUI以及GUI上控件反应的细节定义在view里面
4. All presenter methods called by the view must start with OnXxx() as they are events by design (MVP)
5. Calls from the view to the presenter should be kept at an absolute minimum, and used for "event" type calls only: _presenter.OnViewReady();
View对于Presenter的调用应该尽量少(应该尽量避免)
6. It is FORBIDDEN to use the presenter reference to access the model or services directly, no return values from presenter methods
禁止使用Presenter引用直接调用model或者服务,Presenter中定义的方法应该都没有返回值
7. Calls from the presenter to the view MUST go via the interface only
Presenter中调用View必须通过View的接口进行(View必须继承自接口,且View中可能被Presenter调用到的方法都要定义在这个接口中,Presenter中禁止出现View)
8. No methods in the view shall be public unless they are defined in the interface
View除了已经定义在Display(View的接口)以外的所有方法都应该是私有的(如果不能定义为私有,即Presenter可能要调用,那就应该定义到Display中,这一点和第7条相互印证)
9. It is FORBIDDEN to access the view from anywhere but the presenter, except for loading and showing the view from the CAB ModuleController
禁止从Presenter以外的任何地方调用View(即只有Presenter可以调用View/Display)
10. The interface methods shall have long meaningful names (not "SetDataSource") based on the domain language of the use-case
Display(View的接口)中定义的方法应该使用有具体意义的命名
11. The interface should contain methods only, no properties - afterall the presenter drives the use-case by calling methods, not by setting data
Display中应该只包含方法,不包含属性变量
12. All data in the MVP component should be kept in the model, no data should exist only as properties of UI controls
MVP模式中所有的数据都应该以model的形式出现,除此以外不应该有数据仅以UI属性变量的形式出现
13. The methods of the view interface should not contain UI control name references (e.g. AddExplorerBarGroup) as this makes the presenter know too much about the implementation technology of the view
Display中的方法不应该包含UI空间的名称,比如AddExplorerBarGroup,因为这样的方法名称会使得Presenter知道View里面的具体实现(这条感觉有点太牵强,不过注重细节才专业,才写得出完美的代码)
14. Stick with domain naming in the view methods (e.g. AddTaskGroupHeader), this makes the code easier to understand and the tests self-describing
View里面定义的方法同样应该有具体的意义,应该和这个方法中涉及到的UI空间或者相应的model名称结合起来
笔者补充几点,View和Presenter是单向的操作,View对Presenter一无所知,Presenter对其他的Presenter几乎一无所知,Presenter之间通过各种各样的event和event handler进行数据交互和服务调用。好的UI系统,所有涉及到2个或2个以上Presenter参与的数据或服务交互都必须由A方发出event,B方注册event handler来接收并处理,如果需要返回数据,则B方发出另一个event,A方注册该event的handler,诸如此类。