静态方法、实例方法、构造器

来源:互联网 发布:百度云域名注册免费 编辑:程序博客网 时间:2024/06/09 21:30

静态方法、实例方法、构造器

1. 构造器VS静态工厂方法

有一个RandomIntGenerator 类,产生随机的int类型的整数。如下所示:

public class RandomIntGenerator {  private final int min;  private final int max;  public int next(){...}}

这个生成器接收最大值和最小值两个参数并且生成介于两者之间的随机数。注意到两个属性min和max被final修饰,所以必须初始化它们。可以在定义它们时就初始化或者通过构造器来初始化。通过构造器初始如下:

public RandomIntGenerator(iint min, int max) {  this.min = min;  this.max = max;}

现在,我们要提供给这样一个功能,客户端仅设置一个最小值然后产生一个介于此值和Integer.MAX_VALUE之间的整数。所以我们添加了第二个构造器:

public RandomIntGenerator(int min) {  this.min = min;  this.max = Integer.MAX_VALUE;}

到目前为止,一切正常。但是,我们同样要提供一个构造器设置一个最大值,然后产生一个介于Integer.MIN_VALUE和最大值的整数。我们添加第三个构造器如下:

public RandomIntGenerator(int max) {  this.min = Integer.MIN_VALUE;  this.max = max;}

如果你这样做了,将会出现编译错误:Duplicate method RandomIntGenerator(int) in type RandomIntGenerator。那里出错了?毫无疑问,问题在于构造器没有名字。因此,一个类仅有一个特定方法签名的构造器。同样的,你不能定义方法签名相同的(返回值、名称、参数类型及个数均相同)两个方法。这就是为什么当我们试着添加构造器RandomIntGenerator(int max) 时,会得到上述的编译错误,原因是我们已经有一个构造器 RandomIntGenerator(int min)。

像这样的情况我们该如何处理呢?幸好有其他方式可以使用:静态工厂方法,通过使用简单的公共静态方法返回一个类的实例。你可能在无意识中已经使用过这种技术。你有没有写过Boolean.valueOf?,就像下面这样:

public static Boolean valueIf(boolean b) {  return (b ? TRUE : FALSE);}

将静态工厂应用到RandomIntGenerator类中,得到

public class RandomIntGenerator {  private final int min;  private final int max;  private RandomIntGenerator(int min, int max) {    this.min = min;    this.max = max;  }  public static RandomIntGenerator between(int max, int min) {    return new RandomIntGenerator(min,max);  }  public static RandomIntGenerator between(int max) {    return new RandomIntGenerator(Integer.MIN_VALUE,max);  }  public static RandomIntGenerator between(int min) {    return new RandomIntGenerator(min,Integer.MAX_VALUE);  }  public int next() {...}}

注意到构造器被private修饰确保类仅能通过静态工厂方法来初始化。并且当你使用RandomIntGenerator.between(10,20)而不是new RandomIntGenerator(10,20)来产生整数时你的意图被清晰的表达了。此外,任何类可以提供静态工厂方法替代构造器。

静态工厂的优点:

第一个优点:静态工厂方法拥有名字,这有两个直接的好处:

1. 我们可以给静态方法提供一个有意义的名字2. 我们可以给静态方法提供参数类型、参数个数相同的几个构造器,在传统构造器中是不能这样做的

第二个优点: 不像构造器,静态工厂方法不需要每次在调用时创建一个新的对象。当使用不可变类(immutable class)产生常量对象用于常用值且避免了不必要的重复对象是非常有用的。上面的列子Boolean.valueOf完美的表明了这一点。注意到这个静态方法返回均为不可变Boolean对象TRUE或者FALSE。

第三个优点:静态工厂方法的返回对象的类型可以是返回类型的任意子类型。这使你随意更改返回类型而不用担心影响到客户端代码成为了可能。

记得刚开始的RandomIntGenerator类吗?我们让他复杂一点。假设我们现在想提供不仅能产生整型,而且能产生其他数据类型如String, Double或者Long的随机生成器。这些生成器将有一个next()方法返回一个特定类型的随机对象,所以我们可以先定义一个接口如:

public interface RandomGenerator<T> {  T next();}

RandomIntGenerator的第一个实现类如下:

class RandomIntGenerator implements RandomGenerator<Integer> {  private final int min;  private final int max;  RandomIntGenerator(int min, int max){    this.min = min;    this.max = max;  }  public Integer next(){...}}

String类型的生成器如:

class RandomStringGenerator implements RandomGenerator<String> {  private final String prefix;  RandomStringGenerator(String prefix) {    this.prefix = prefix;  }  public String next() {...}}

注意到所有的类及类的构造器被定义为包私有范围(默认的可见范围)。这意味着除本包之外的客户端代码无法创建这些生成器的实例。那我们该怎么办?提示:它以“static”开始,以“methods”结束。考虑下面这个类:

public final class RandomGenerators {  private RandomGenerators() {}  public static final RandomIntGenerator<Integer> getIntGenerator() {    return new RandomIntGenerator(Integer.MIN_VALUE, Integer.MAX_VALUE);  }  public static final RandomGenerator<String> getStringGenerator() {    return new RandomStringGenerator('');  }}

RandomGenerators类成为了一个不可实例化的工具类,它与静态工厂方法没有什么区别。在同一个包中,不同的生成器类可以高效的获取和实例化这些类。但是,有意思的部分出现了。注意到这些方法仅返回RandomGenerator 接口,这才是客户端代码真正需要的。如果它获得一个RandomGenerator它就知道调用next()然后得到一个随机的整数。
假设下月我们编写了一个新的高效的整数生成器。只要让这个新类实现了RandomGenerator我们更换静态方法中的返回类型,那么所有客户端代码神奇的使用了新的实现。

2. 静态工厂方法VS实例工厂方法

静态工厂方法:直接可以通过静态方法来实例化一个对象

public class HelloWorldFactory {  public static HelloWorld getInstance() {    retrun new HelloWorld;  }}HelloWorldFactory.getInstance();

创建HelloWorld对象直接可以调用getInstance方法来进行实现

实例工厂方法:先创建类对象,通过对象来调用创建实例对象的方法

public class HelloWorldFactory {  public HelloWorld createHelloWorld(){    return new HelloWorld();  } }HelloWorldFactory helloFactory = new HelloWorldFactory();helloFactory.createHelloWorld();
原创粉丝点击