转于自己在公司的Blog:
http://pt.alibaba-inc.com/wp/experience_760/generic_vs_composite_expansibility.html
我们平台的产品越来越多,产品的功能也越来越多,
平台的产品为了适应各BU和部门以及产品线的需求,
势必会将很多不相干的功能凑在一起,客户可以选择性的使用,
为了兼容更多的需求,每个产品,每个框架,都在不停的扩展,
而我们经常会选择一些扩展的扩展方式,也就是将新旧功能扩展成一个通用实现,
我想讨论是,有些情况下也可以考虑增量式的扩展方式,也就是保留原功能的简单性,新功能独立实现,
我最近一直做分布式服务框架的开发,就拿我们项目中的问题开涮吧。
比如:远程调用框架,肯定少不了序列化功能,功能很简单,就是把流转成对象,对象转成流,
但因有些地方可能会使用osgi,这样序列化时,IO所在的ClassLoader可能和业务方的ClassLoader是隔离的,
需要将流转换成byte[]数组,然后传给业务方的ClassLoader进行序列化,
为了适应osgi需求,把原来非osgi与osgi的场景扩展了一下,
这样,不管是不是osgi环境,都先将流转成byte[]数组,拷贝一次,
然而,大部分场景都用不上osgi,却为osgi付出了代价,
而如果采用增量式扩展方式,非osgi的代码原封不动,
再加一个osgi的实现,要用osgi的时候,直接依赖osgi实现即可。
再比如:最开始,远程服务都是基于接口方法,进行透明化调用的,
这样,扩展接口就是,invoke(Method method, Object[] args),
后来,有了无接口调用的需求,就是没有接口方法也能调用,并将POJO对象都转换成Map表示,
因为Method对象是不能直接new出来的,我们不自觉选了一个扩展式扩展,
把扩展接口改成了invoke(String methodName, String[] parameterTypes, String returnTypes, Object[] args),
导致不管是不是无接口调用,都得把parameterTypes从Class[]转成String[],
如果选用增量式扩展,应该是保持原有接口不变,
增加一个GeneralService接口,里面有一个通用的invoke()方法,
和其它正常业务上的接口一样的调用方式,扩展接口也不用变,
只是GeneralServiceImpl的invoke()实现会将收到的调用转给目标接口,
这样就能将新功能增量到旧功能上,并保持原来结构的简单性。
再再比如:无状态消息发送,很简单,序列化一个对象发过去就行,
后来有了同步消息发送需求,需要一个Request/Response进行配对,
采用扩展式扩展,自然想到,无状态消息其实是一个没有Response的Request,
所以在Request里加一个boolean状态,表示要不要返回Response,
如果再来一个会话消息发送需求,那就再加一个Session交互,
然后发现,原来同步消息发送是会话消息的一种特殊情况,
所有场景都传Session,不需要Session的地方无视即可。
如果采用增量式扩展,无状态消息发送原封不动,
同步消息发送,在无状态消息基础上加一个Request/Response处理,
会话消息发送,再加一个SessionRequest/SessionResponse处理。