转眼又有几天没有做总结了,近段时间被接口的对接事情烦到心情十分糟糕.每次遇到这种事情我都喜欢沉下去看一下最原始的东西,所以最近看一些有关接口方面的知识,里面提及最多的一个规范就是一个接口做一件事情.这个说的就有点广义了,到底什么叫做一个接口做一件事情呢?
去年在做商品管理的时候有一个上下架的问题.当时和我配合的是一位高工,一个上下架的的问题,他给我整了4个接口,上架,下架,批量上架,批量下架.我对他的设计很不感冒,在我眼中这应该就是一个接口,或者是说最多分为2个接口.当时他就给我好好的教育一番,严重的指出了一件事情一个接口,上架就只负责上架哪怕是错了绝对不影响下架.从严格意义而言我很赞成他说的,可是问题在于就个人觉得在没有出现代码问题的情况下我不觉得有可能出现下架错了,上架继续正常使用的情况.然而还没让我更深刻认识到这个问题的时候他另谋高就了,继承他的程序员做了一个很有意思的事情,将他做的4个接口整合然后再封装成4个给我,这时候我就实在不明白它的意义所在了.
为此我特意跑到公司架构师那里死皮赖脸的问了一翻,他给我的解释对于这类型的接口合并也好分也好都是合理,对于接口而言有一个泛的定义,我们能把上下架当成一件事情,也能把他们分别当成一件事情,在这种情况下我们尽可能的在不让接口泛的前提下保持合并.什么是泛?比如你上架可以传参memberID.productID 也可以memberID.productID ,stat
同时memberID,可以定义成string,array().假如你用3个参数array()->memberID.productID ,stat,你就能将4个接口整合,这3个参数都能成为方法的必要属性,这种是在泛的范围内的!再比如收藏,商品收藏需要memberID,productID 圈子收藏memberID,circleID 这时候要合并需要添加一个stat来判断是那一种,而这个stat不用来插入数据库,这已经就是泛的边缘化了.然后进一步,如果收藏圈子需要一个备注,那么圈子收藏memberID,circleID,stat,remark,那么这就是一种泛了,让接口复杂化了!
事情总是这么有意思,最近我们又接口重构了,我们还是拿上下架来说把,一下是那同事的接口简介:
------------------
访问:/productServiceExporter
service: com.csc.product.client.ProductService
方法替换:updateProductStatus
返回值:1成功 非1失败
参数:String memberId(会员ID),String productId(产品ID),String checked(修改状态(Y上架、A下架)删除时不传),String isdelete(删除(Y)上下架是不传)
undercarriageProdProductMain groundingProdProductMain
访问:/productServiceExporter
service: com.csc.product.client.ProductService
方法替换:updateBatchProductStatus
返回值 1失败 大于0 则成功
String memberId,List<String> productIds(产品ID集合),String checked(修改状态(Y上架、A下架)删除时不传),String isdelete(删除(Y)上下架是不传)
groundingProducts undercarriageProducts
------------------
不可否认,现在一般都是逻辑删除,可以用一个字段表明了商品状态,但是能写出以上的接口,我实在已经不知道如何去和他说什么了!不可否认,所有的上下架,删除我们可以用一个接口完成,但是我们还需要注意一点,业务逻辑的问题,从业务逻辑而言,我们不应该将他们合并在一起,因为接口是全站的不是单独为了一个小模块而生成的!
有点抱怨的情绪在里面,有点啰嗦!说了这么多一直在说接口的定义方面,其实接口设计的好与坏更大程度的体现在了返回值上!
说到这里我不得简要说明一下DTO,VO对象, 对于分层模式而言,接口对应的就是这2层!DTO作为接口间交互的一种对象,VO是渲染对象,就比如一个DBO商品产品详情包含几十个字段,那么当我需要一个产品详情的VO对象时候,我就需要多个接口通过DTO组成一个可以直接可渲染的VO,这里面已经将所有的分类,类别,属性等可视化(为什么不直接一个数据库链表查询,而通过这么多的接口对接组合,不久后我会写一个关于memcache的贴子中写明),而如果我需要一个列表我可能只需要ID,title,time几个简单的字段,这样同样是商品VO,就是2个不同的VO对象了.因为我在列表中没必要那么多商品信息,这是一种资源的浪费,然而大部分情况下是为了方便直接作为一个对象给我,这样在列表数据的时候,对资源的损害,对响应时间都是很不好的(尤其是跨语言)!
前不久,有一个小需求就是在商家信息里面增加一个是否提供加工,在后台是以radiobutton进行选择的,然而后台设计很显然的将字段赋值为0,1.更顺理而然的做出接口返回0,1.由前端再去封装那句“是否提供加工”.我对这个接口很不满意,因为作为输出给前端的我一直定义为可以直接渲染的,这样就能很明确的保证了接口的变动和扩展性,当时我就去找这位同事讨论,他给出的解释是:在接口中我怎么能直接写死返回值呢? 这时我不得不找个十分严格的理由来说服他->是否提供加工只是对一些原料商什么的,布料商呢?是不是应该是是否染色,食品商呢?是否过期包换....那么那个radiobutton前面是不是会变成一个下来列表,对应的数据从另外的一个信息表中读取?这时候你怎么办,这时候返回一个信息ID,0/1给前端?前端再去调接口组装数显示?还是由你组装字符串 不论哪种改变都会牵涉到接口的变动,而不是接口内部调整,那为什么我们不做好预留直接输出string?让前端舒舒服服的去渲染?
顺便提一下,在已接口模式去完成项目的时候注意别偷懒,做好文档规范,一定要细!每次接口有任何变动要做到能掌控全局,当你不这样做的时候,就会出现一种情况,接口和DTO的泛滥,仅仅是调一个简单的信息,也许都可能出现数十个接口...