写在开头:走技术这条路永远也不能停止学习,工作快三年了,虽然一直都有坚持学东西,也经常在各大技术论坛闲逛,不过挺遗憾自己没有把学习的收获和心得记录下来,正好最近也不是很忙,就把之前的东西再重新理一遍,也正好做个记录。想了一下,还是从《Effective Java》开始吧,这本书我相信很多搞Java的人都看过,这算是我第二次从头看这本书吧,感觉在掌握了Java的基础并做了一些东西之后再来学习这本书真的是受益匪浅。
下面是我认为这本书的几个最重要的作用:
1.更深入地理解Java的核心特性。
2.更高效地使用Java及其基本类库。
3.培养良好的编码风格和编码习惯(正如作者所说本书关心如何编写出清晰、正确、可用、健壮、灵活和可维护的程序)。
这本书是按照主题和条目来组织的,每一章是一个主题,每一个条目是作者的一个建议,如果你希望自己在技术的路上少走弯路、不断进步的话,可以说每一个建议都非常有用。
我这里只是对作者的每条建议做一个学习的记录,不敢有太多自己的理解,用尽量少的语言概括描述一下,例子也大多会用原书中的例子。
好了,终于介绍得差不多了,废话不多说了,进入正题:
第1条--考虑用静态工厂方法代替构造器
既然要用静态工厂方法代替构造器,那首先得知道静态工厂方法是什么,有什么优势。
这里说的静态工厂方法不是设计模式中的工厂模式,而是通过一个静态的方法返回类的实例,这个大家肯定都用过,单例就是一个例子。
下面是Boolean类型的示例:
public static Boolean valueof(boolean b){
return b?Boolean.TRUE:Boolean.FALSE
}
静态工厂方法与构造器不同的第一大优势在于,它们有名称。通过方法名可以较为准确地描述返回的对象实例。另外,构造器在参数相同的情况下只能通过参数顺序的不同来区分,这种构造器非常容易混淆,静态工厂方法可以有效地避免这种麻烦。
静态工厂方法与构造器不同的第二大优势在于,不必在每次调用它们的时候都创建一个新对象。这个优势在某些情况下极为明显,还是拿Boolean类型来说明,Boolean.valueof(boolean)从不创建对象,Boolean.TRUE和Boolean.FALSE都是final的,它们只在初始化时创建一个实例,以后每次调用valueof方法都返回相同的实例。可以设想,如果每次都创建一个新的Bolean实例,在频繁使用的情况下将造成多大的内存浪费。
静态工厂方法与构造器不同的第三大优势在于,它们可以返回原返回类型的任何子类型的对象。用户只需要通过接口来引用被返回的对象,而不需要关注具体的实现类。这里原书中举了三个例子,这三个例子从不同的角度描述了这种方式的优势。
第一个是例子是java.util.Collections,在它的内部有很多Collection的非公有实现类(包括不可修改的集合、同步集合),这些实现类都通过静态工厂方法导出。这极大地减少了API的数量,用户不需要在一大堆的API文档前做选择了。
第二个例子是java.util.EnumSet,它根据底层枚举类型的大小来返回不同的实现类,这么做的好处是显而易见的,在它的后续版本中假如需要增加或者删除一些实现类对于它的使用者是没有任何影响的。
第三个例子就是服务提供者框架,最典型的应用就是JDBC。先来了解一下服务提供者框架的三个重要的组件:服务接口(Service Interface),这个是由提供者来实现的;提供者注册API(Provider Registration API),这是给服务提供者注册的接口;服务访问接口(Service Access API),是用户用来获取服务实例的。对于JDBC来说,Connection就是服务接口,DriverManager.registerDriver是提供者注册API,DriverManager.getConnection是服务访问API。这个框架的好处就是在编写时不需要先有服务提供者的具体实现。
静态工厂方法的第四大优势在于,在创建参数化类型实例的时候,它们使代码变得更加简洁。下面看一个对比:
方式1:Map<String,List<String>> m = new HashMap<String,List<String>>();
方式2:Map<String,List<String>> m = HashMap.newInstance();
你更喜欢哪种?毫无疑问是第2种方式,虽然这个例子的类型参数还不足够复杂。HashMap目前还没有提供这个静态工厂方法。
静态工厂方法的主要缺点在于,类如果不含公有的或受保护的构造器,就不能被子类化。它鼓励使用复合,而不是继承。如果你的类设计就是用来继承的,那就不能把构造器设置成私有的了。
静态工厂方法的第二个缺点在于,它们与其他的静态方法实际上没有任何区别。这个只是在API中不能明确地知道哪个是静态工厂方法,一般静态工厂方法都使用下面一些惯用的名称:valueof、of、getInstance、newInstance、getType、newType.
构造器和静态工厂方法各有利弊,在设计一个类的时候尽量优先考虑静态工厂。