创建和销毁对象

     想写一下关于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模式的客户端代码将更易于阅读和编写。

猜你喜欢

转载自newboy2004.iteye.com/blog/2267228