想写一下关于Java高效开发的一些方法总结,作为自己技术提升的一种必要反省。同时为我们在每一次编写程序代码时,更多的考虑一下我们这样写代码是不是更高效,更简单的一种方法。
今天第一次写,后续会陆续发出关于Java高效开发的一些总结文章。希望有任何想法的Java同行们一同共勉,同时编写博客也是为了训练自己的表达的能力,作为技术成长的一个见证。好了,废话不多说。
对象的创建和销毁
对象的创建,我们都知道,采用new这种方式。同时提供默认的无参构造方法就可以。对于一些必要的参数我们想在new对象的时候就初始化,可以复写或者叫重载多个参数的构造参数new对象。这种情况我们在编写大部分的程序的时候都遇到过,但是也有一些特殊情况,比如我们的对象确实有很多数据域构成,这时候在采用这种构造方法重载的情况,感觉就有点繁重而且不好理解。对于new对象的时候 就有些累赘,所以我们应该考虑这种情况下 我们怎么才能更好的new我们的对象。
第一种方法,考虑用静态工厂的方式替代构造器
这种方式我们在编写所谓的单例模式类的时候,通过会这样做。就是提供默认的私有构造器,同时提供一个返回该类实例的一个public static 的静态方法,防止new出多个该class的对象来,以实现我们的单例类。
还有在Java JDK中经常看到这种代码Integer.valueOf(xxxx),这种类型转换的方法,这也属于静态工厂方法,
采用这种方法的好处,我们也说一下:
a,它们有一个更好理解的名称,正如上面所描述的那样,如果有多个构造参数的话,你根本不知道它们的具体含义,如果说你们在不看文档注释的前提下;还有一个问题是,连我自己也会忽略的一个问题是,对于多个数据域的class我们未必会给每个数据域都加上一个可以理解的注释,这是每个程序员都有或存在的问题(ps:如果你没有的话,请自行略过该段)。所以,当一个类需要多个带有相同签名的构造器时,考虑用静态工厂方法来替代它吧,并选择一个别人能见名知意的方法名
b,不必在每次调用他们的时候都创建一个新对象,这样可以省掉很大的一些new对象的开销,我们可以预先创建好对象,然后把它缓存起来,等到使用时直接拿来用即可。避免创建不必要的重复对象。其实这里能更好回答这个问题的就是singlton模式了。
c,它们可以返回原返回类型的任何子类型的对象,这样在返回对象时,又有了更大的灵活性。这一点可以参照,JDK 5中的Collection Framwork的不可修改集合,同步集合等,他们都是通过静态工厂方法在一个不可实例化的类中导出的。
这里我们提及一下服务提供者框架(Service Provider Framework),它有三个重要的组件:服务接口(Service Interface),这是提供者实现的;提供者注册API(Provider Registration API),这是系统用来注册实现,让客户端访问他们的;服务访问API(Service Access API),是客户端用来获取服务的实例的。服务访问API是”灵活的静态工厂“,它构成了服务提供者框架的基础。还有一个是服务提供者接口(Service Provider Interface)它是可选的组件,它负责创建其服务实现的实例。举个经常使用的例子,对于JDBC来说,Connection就是的它的服务接口,DriverManager.registerDriver是提供者注册API,DriverManager.getConnection是服务访问API,Driver是服务提供者接口。
d,在创建参数化类型实例的时候,它们使代码变得更加简洁,这个可以参照Collection Framework中的源码实现。
静态工厂方法的缺点有两点:
一是类如果不含有公有的或者受保护的构造器,就不能被子类化,
二是他们与其他的静态方法实际上没有任何区别,这的意思是说,在jdk中没有明显标识出来。对于有多个方法的类来说,找到一个实例化类的静态工厂方法也是非常困难的。
第二种方法,遇到多个构造参数时,考虑采用构建器(builder)
它同样和静态工厂方法一样,适合有多个构造参数时使用的另一种构造对象的方法。
package cn.effectivejava.createobject.bulider; /** * 采用构建器模式创建对象实例 * @author qd * */ public class NutritionFacts { private final int servingSize;//required private final int servings;//required private final int calories;//optional private final int fat;//optional private final int sodium;//optional private final int carbohydrate;//optional public static class Builder{ //required parameters private final int servingSize; private final int servings; //optional parameters private int calories=0; private int fat=0; private int carbohydrate=0; private int sodium=0; public Builder(int servingSize,int servings) { this.servingSize = servingSize; this.servings = servings; } public Builder calories(int val){ this.calories= val; return this; } public Builder fat(int val){ this.fat=fat; return this; } public Builder carbohydrate(int val){ this.carbohydrate = val; return this; } public Builder sodium(int val){ this.sodium =val; return this; } public NutritionFacts build(){ return new NutritionFacts(this); } } private NutritionFacts(Builder builder){ this.servingSize=builder.servingSize; this.servings = builder.servings; this.calories=builder.calories; this.fat = builder.fat; this.sodium =builder.sodium; this.carbohydrate =builder.carbohydrate; } }
我们可以采用如下方式,构建对象:
NutritionFacts cocalCola = new NutritionFacts.Builder(240, 8) .calories(100).sodium(35).carbohydrate(27).build(); System.out.println(cocalCola.calories);
这里我们可以和设计模式中的builder模式参照对比来学习和理解该模式的应用方式和场景。
与构造器相比,builder的微略优势在于,builder可以有多个可变参数。构造器就像方法一样,只能有一个可变参数。因为builder用每一个方法来设置参数,你想要多少个可变参数,就可以有多少个可变参数。
它还可以结合泛型的方式构建各种对象,也可以采用有限制的通配符类型来约束构建器的类型参数。
简而言之,如果类的构造器或者静态工厂中具有多个参数,设计这种类时,Builder模式就是种不错的选择。特别是当大多数参数都可选的时候,相比其他方式,使用Builder模式的客户端代码将更易于阅读和编写。