Smart Client Software Factory 是一个关注 Smart Client (智能客户端)构建的 UI 层框架,提供了对 MVP 模式的 First Class 支持,不了解 MVP 模式就不能完全领会 SCSF 的思想精华。
本篇及后面两篇将结合 Smart Client Software Factory 讲解 MVP 模式及面向对象设计原则,要点:
上一篇创建的 StopLight 项目演示了如何使用 SCSF构造基于 MVP 模式的应用。StopLight 功能很简单,实现这样的需求很多人只用一个窗体类就可以搞定,而且代码量不会太大,理解维护起来不会太困难;使用 SCSF 的 MVP 构建却涉及到了 10 个左右的类,并且初看起来里面的关系也变得扑朔迷离,难以捉摸。
这牵扯到一个普遍问题,框架、设计模式和良好的面向对象设计往往使系统类的数量增加,类之间的关系动态化,初看起来不容易了解,甚至令人望而生畏。因此很多人,尤其是用惯了 Windows 开发平台的开发人员,认为很多模式和框架(例如今天我们讨论的 MVP )虽然理论上看上去很美,但工程上似乎不太实用。Java 社区过多的研究模式,框架等理论,导致设计模式、框架的过度使用和滥用,确实拖累了很多项目。
今天,.NET 社区对框架、设计模式的追崇也慢慢的跟进 JAVA 社区,IOC,MVP,MVC,SOA,ESB等等一系列的架构理论都有了相应的框架实现。今天我们通过这个小题大做的 StopLight 来理解一下 MVP 究竟能够我们带来什么,我们又因此付出了什么代价,并初步讨论什么样的项目适合使用 SCSF。
MVP 模式(Model-View-Presenter)是由 MVC模式(Model-View-Controller)演变来的 UI 层框架模式,MVP 模式本身往往有多个设计模式组成。MVP 和 MVC 都采用了抽象的方式将界面部分划分为相对独立的多个模块,并通过面向抽象编程(面向接口编程)来降低模块间的耦合性,SCSF 利用依赖注入方式进一步使构建松散耦合的 MVP 应用变得方便。MVP 与 MVC 的比较将在后面的文章中介绍。
该结构图表示 View 直接和 Presenter 交互,Presenter 与 Model 交互,View 和 Model 直间没有直接联系。同时 Presenter 通过接口与 View 交互。
SCSF 中的 MVP 实现完全按照上图模型实现,当我们使用 Add View(With Presenter)Guidance Package 生成 View 时,SCSF 为我们生成了三个类,本例中是IStopLightView ,StopLightView ,StopLightViewPresenter 。
我们首先来看 Presenter ,在创建 SCSF 解决方案时,Guidance Package 自动在 Infrastructure 项目的接口层中(本例是 namespace SmartClient系列.Infrastructure.Interface)创建了一个抽象的 Presenter 类:
里面的 View (TView 类型)代表的就是 MVP 中的 V ,WorkItem (WorkItem 类型,通过 [ServiceDependency] 注入)代表了 MVP 中的 M (也可以认为 WorkItem 中承载了 Model,通过 WorkItem 我们可以获取所谓的 Model)。因此 Presenter 与 View 和 Model 建立起了关系。
再来看 StopLight 项目中的 V 部分由类 StopLightView 和接口 IStopLightView 组成,StopLightView 继承自 UserControl 并实现了 IStopLightView 接口:
在 StopLightView.GeneratedCode.cs 文件(StopLightView 的分部类)中代码如下:
我们通过 [SmartPart] Attribute 标志该类(StopLightView)是一个 SmartPart(SCSF 中的概念,代表一个视图部件)。我们在 ObjectBuilder 部分介绍过,构造 StopLightView 对象时,SCSF 看到 Presenter 属性前面的 [CreateNew] Attribute 会自动创建一个 StopLightViewPresenter 对象附给 _presenter 字段,而 _presenter.View = this 语句表明新创建的StopLightViewPresenter 实例的 View 属性设置为 StopLightView 实例。
这样 View 就与 Prensenter 建立起了双向关系,StopLightView 实例具有了 StopLightViewPresenter 实例的引用,一种强耦合的引用。
值得注意的是,StopLightViewPresenter 的实例的 View 属性是在抽象类 Presenter 中定义的 <TView> 泛型类型,StopLightViewPresenter 的具体实现是:
也就是说,在 StopLightViewPresenter 类中,TView 泛型类型代表的是 IStopLightView 接口 ,因此 Presenter 与 View 通过接口进行联系,是一种松散的耦合。这与上面介绍的 MVP 结构中说的 Presenter 通过接口与 View 交互完全一致。
Model 是一个比较宽泛的概念,一般认为业务逻辑实体、服务组件等都可以看作 Model,StopLight 项目从 Unity 的 QuickStart StopLight 移植而来,没有利用 SCSF 的 WorkItem 概念,而是直接在 Presenter 类中通过依赖注入方式与 Model 建立联系,看下面例子中的 Stoplight 和 StoplightSchedule:
这里, StopLightViewPresenter 与 Stoplight ,StoplightSchedule 两个业务逻辑实体类是一种强的耦合关系,代表了 MVP 结构中 Presenter 与 Model 的关系。 在 SCSF 中,推荐的设计方式是所有的 View 和 Model 都驻留在该用例对应的 WorkItem 中,关于 WorkItem 后面会专门介绍到。
下一部分会介绍设计 MVP 应用的具体实践、设计原则并简要分析优缺点。
【FLYabroad】 SCSF 严格按照标准 MVP 架构模式构造 UI 层,代码和架构完全吻合,给我们设计 MVP 应用提供了良好的参考。