程序的扩展,毋庸置疑是每个程序员都会考虑的问题。在Java世界里,一般有哪些扩展方式呢?想必大家都清楚,接口、反射或者代码生成。
用接口做扩展,一般在是定义一个接口,使用者代码针对接口编写,由实现者完成具体逻辑。接口和实现的关联可以直接创建,工厂方法,依赖注入等等。
用发射和代码生成一般来说是预先指定了一些编码约束和使用约束,换句话说就是定义了一个协议,使用者通过这个协议描述的方式使用实现,实现则也通过协议描述的方式与接口关联。好比说我要获得一个对象的某个属性,就可以动态的调get××方法。
现在我介绍一个新的扩展方式。这个方法完全基于最基本的java编程方式,而且大家肯定都非常熟悉,但是作为扩展点估计很少有人试过。
我把这种方式成为“缺省点 ”,是无意中从slf4j这个项目实现发现的http://www.slf4j.org/
slf4j的介绍大家可以上网站慢慢看,简单点说它就是一个日志的facade(请恕我不知如何翻译这个词,权且称“门面”吧)。
slf4既然是个面子工程,实现就肯定少不了了。
那么,在实际使用时,又需要做什么样的操作,才能将使用者与实现者关联起来呢?
答案是除了基本的jar包的部署,其它什么都不需要。
因为这个slf4j的面子超大,实现放进来就必须给它面子,否则别想干活。
为了达到这一效果,slf4j在暴露给外部使用的主类org.slf4j.LogFactory中,使用了一个特定的类org.slf4j.impl.StaticLoggerBinder,但这两个类没有打包在一起,前者打在核心的api包中,后者则有实现包提供。
明白了缺省的意思了吧:)
不管是谁,只要定义了org.slf4j.impl.StaticLoggerBinder这个类,org.slf4j.LogFactory被调用时,java的类加载机制就会自动的找到实现,而实际的操作就通过org.slf4j.impl.StaticLoggerBinder传到了实现包中。
是不是有点缺省即配置的味道,所以我称它为“缺省点 ”。
这种方法的好处是无需仍和配置文件,只要部署环境中能找到这个缺省点的实现,就可以直接关联起来。
但是这种方法编写程序的时候就需要注意了,为了让程序通过肯定需要给缺省点定义空的实现,但是部署时又不能把这些实现一并打包,否则会影响对其它实现的搜索。
也很容易看出,这种扩展的方法的局限也是蛮大的,扩展点只能有一个类,但是像slf4j这样,作为一个简单的桥梁最合适不过了。
核心api包中定义Log接口并暴露一个LogFactory方法。需要使用日志的其它对象,通过调用LogFactory生成具体的Log。但是LogFactory并不实际生成Log,而是将请求转到StaticLoggerBinder所在的实现包,由实现包负责生成Log。