前一阵子做了iOS集成新浪微博SDK并实现部分功能的工作,这里正好将事后反思的内容总结一下,欢迎喷冷水。
假定需求是这样:在已经使用微博登陆的前提下,查找一个人的所有好友,筛选出其中年龄、性别等属性符合一定规则的人,然后查找这些人所有的微博,将这些微博按照一定的条件组织并且展示。
首先说明一下,查找好友和查找微博的做法,都是通过网络请求向新浪API请求数据,而登陆则可以通过SDK来简单实现。
那么,从上述描述当中,我们看到了两个大的用例,一个是登陆,一个是后面描述的一系列操作。
首先说登陆这件事,抛开应用程序需求来说,登陆有很多种方式,比如微博、微信、Facebook等等,而对于一个应用来讲,登陆只是一个上层的用例,那么我们就有必要为登陆这个动作提供一个操作(也可以叫事件或者服务),在它的内部来对登陆方式做判断,并且向下调用具体的登陆逻辑,那么这当中就需要用到策略模式或者工厂模式来区分不同情况。
再者,不论任何程序,都有可能做登陆,那么这个登陆服务,一定是一个与具体业务逻辑无关的通用模块,是应该从整个系统当中独立出来保证能够复用的。而再看后面的查询操作,则是和具体应用有关的,因为需求不同,所以没法复用到另一个应用当中,那么它只不过是应用程序当中的一个事件,两个需求完全不是一个层级的。
登陆,是上层事件,能够独立,查询,是下层事件,无法独立。
下面从技术方面来看,登陆登出不光能用微博SDK,同样也可以利用微博API来实现,也就是说这两者同样使用了微博的东西,那么就有必要使用一个WeiboFacade层来对具体的通信和数据解析做封装,可以分为针对SDK的封装以及针对API的封装。
再看一下上面的假定需求,可以拆解为这样几部:1.查好友,2.筛选,3.查微博,4.筛选。其中1和3是需要调用微博API的,那么我们的程序就可以直接对WeiboFacade进行调用了。这里有一样东西不能忽略,那就是API接收的参数和返回的数据,有些人管这个叫VO,也有叫DTO的,总之,这种数据对象,一定是要定义在对微博进行包装的包里的,而不是散落在外侧代码逻辑当中,这种数据结构泄露的直接后果就是模块无法复用,以及这个模型的语义容易和程序业务内的一些语义造成耦合。
而其中2和4两步完全是业务需求相关的,也就是说,不能将它们写在对微博封装的包里,而1234四件事又组成了一个用例,那么按照一开始分析的,就需要一个RequestService(也可叫别的)来封装这些用例,对这个需求,在这个Service当中定义一个方法,其中13两步调用微博的WeiboFacade,24两部直接写在这个方法当中。
如此一来就初步地将业务逻辑和第三方库剥离开了,第三方库的封装包应该放在基础设施层。然而这样做还面临一个极端问题,那就是,一旦第三方库的API发生变动(尤其是当参数变动时,这种情况在某些WebService开发当中很常见),很有可能导致RequestService对WeiboFacade的调用出现问题,也就是说有必要将这两层再隔离开,让下层变动对上层的影响尽量小,并提供一些容错机制,一个方案是在WeiboFacade上层添加一个Adapter层,或者说是某种协调层,作为底层的异常边界。
总之,大体思路就是Service - | - Adapter - Facade - 第三方。
之前的工作由于时间原因及需求并不复杂,并没有实现一套很好的封装,直接定义了一个Service里面用方法包装了所有对微博的调用,只是起到了简单的隔离作用。