一、用静态工厂方法代替构造器
类通过共有的构造方法可以提供很大的优点:
1、构造方法可一有不同的名字,我们可以通过名字区分构造什么样子的对象,而构造器名字相同,当参数列表的数目相同 顺序不同时 很大的可能会用错构造方法。
2、可以每次调用他们的时候都使用相同的对象(单例模式),可以对一个对象重复的利用,而每次调用构造方法都会新建一个对象。当程序需要创建相同的对象或者创建对象的代价很高时,使用静态工厂是一个很好的选择。
3、使用静态工厂可以返回原返回类型的任意子类型。在静态工程方法中可以根据不同的条件返回不用的对象。
服务提供者框架:多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把他们从实现中解耦出来 减少服务提供者之间的关联。
4、使用泛型 创建参数化类型实例的时候 可以让代码更简洁。
编译器可以通过静态工厂来找到类型参数。
静态工厂方法
以Java中自带的Boolean类(基本类型boolean的包装类)为例,它的静态工厂方法为:
public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}
我们应该考虑用该方法替代构造器来获得一个Boolean的实例。
//使用构造器
Boolean b1 = new Boolean(true);
//使用静态工厂方法
Boolean b2 = Boolean.valueOf(true);
同样是传入一个true
作为参数,两种方法有什么区别呢?
静态工厂方法的优点
优点1:它们有名称
假如我们想要提供多个具有相同签名的构造器,这在Java中是做不到的,除非把参数列表的顺序做些调整,但这会对用户很不友好。因此可以使用静态工厂方法,取不同的名字以表示不同的构造方式。
优点2:不必每次都创建新对象
适用于单例模式。
优点3:构成基于接口的框架
静态工厂方法返回对象所属的类可以是后来动态添加的。我们以服务提供者框架(Service Provider Framework)为例讲解,该框架的代表是JDBC API。
优点4:创建泛型类实例的代码更为简洁
请看下面两种创建泛型类实例的方式,后者比前者更为简洁。
//使用构造器创建
Map<String, List<String>> m1 = new HashMap<String, List<String>>();
//使用静态工厂方法创建
Map<String, List<String>> m2 = HashMap.newInstance();
前提是HashMap提供的静态工厂方法newInstance
定义如下
public static <K, V> HashMap<K, V> newInstance() {
return new HashMap<K, V>();
}
这种情况下,编译器可以通过返回值类型推断K、V的具体类型。
静态工厂的缺点:
类如果不含有共有的或者受保护的构造方法,就不能被子类化。
当使用静态工厂时,就是一个普通的static方法,在API文档中,构造方法有单独的区域,而静态方法不会被分割出来。
我们一定要考虑使用静态工厂!
二、遇到多个构造器参数时要考虑用构建器
当创建对象的时候需要大量的可选参数,那么静态工厂和构造器就不是好的选择。可以采用的方式:
1、重叠构造器:提供第一个只有必要参数的构造器,第二个构造器包含一个可变参数 然后两个可变参数一次类推 用this( )来调用 直到所有的可变参数都包含。
但是当有很多参数的时候,客户端代码会很难写 并且难阅读。
2、javaBeans模式 用setter 对属性进行赋值,来设置必要参数和可变参数 但是当构造过程被分到了几个调用中,在构造过程中javaBeans会出现不一致的状态,即多线程的情况。
3、一种好的模式(Builder模式)
不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造器(或者静态工厂),得到一个builder对象。然后客户端在builder对象上调用类似于setter的方法,来设置每个相关的可选参数。最后,客户端调用无参的build方法来生成不可变的对象。
bulder可以是多个可变的参数。
对多个参数加约束条件时 可以用setter进行设置
构建器缺点:
1.构造器写起来很复杂
2.创建对象开销比较大
所以构建器模式只适用于需要传入很多种情况参数的时候,比如大于4种参数的配合,才比较划算。