静态初始化工厂

     在实例化过程中,通过不同的描述性方法名来显示哪些参数需要传递。在一些情况下,哪些参数可以由方法名知道无需传递。新手可能会觉得这种方法无法用于对象实例化和初始化,理由是Java中类的构造函数必须与类同名相同。这意味着构造函数仅能通过同名函数重载。幸运的是,Josh Bloch在每一版 Effective Java的第一章都会解释这个问题。按照Bloch的说法,我们可以使用静态初始化工厂实例化类。这样做的好处之一是,我们可以用任意合理的方式命名方法。

下列的代码为我们展示了静态初始化工厂的功能。当我实现这些功能时,我喜欢定义一个或几个只提供静态初始化工厂调用的私有(标记为private,不能被其它类调用)构造函数。只有我定义的类必须使用这样的方式初始化,其他人使用静态初始化工厂初始化会更加简单。这样把参数很多的构造函数隐藏了起来,可以让这些构造函数的声明完全满足需求。具体地说,如果构造函数要求参数传入空值,可以通过定义不同的静态初始化工厂方法解决。这样调用者不必特意为这些参数传递入空值,而是由静态初始化工厂方法代替客户为构造函数传递空值。简而言之,静态初始化工厂方法为用户呈现了一个更整洁、更友善的接口并且隐藏了类定义中的带有过多参数构造函数。由于构造函数无法自定义方法名,无法直接使用重构解决参数过多的问题。如果需要,静态初始化工厂方法可以接受“原始”类型参数并在内部把它转为通用类型和参数对象,这是静态初始化工厂方法的另一个优势。以上所说的功能在下面的示例代码中一一列举了出来:

静态初始化工厂验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/**
  * 构造函数标记为private,因为只有内部构造器会调用它创建实例。
*
  * @param newName Name of this person.
  * @param newAddress Address of this person.
  * @param newGender Gender of this person.
  * @param newEmployment Employment status of this person.
  * @param newHomeOwner Home ownership status of this person.
  */
  privatePerson( String newName, String newAddress, String newGender,
String newEmployment,
String newHomeOwner)
  {
  this .name = newName;
  this .address = newAddress;
  this .gender = newGender;
  this .employment = newEmployment;
  this .homeOwnerStatus = newHomeOwner;
}
 
public static Person createInstanceWithNameAndAddressOnly(
  String newName,StringnewAddress)
  {
  return new Person(newName, newAddress, null , null , null );
  }
 
public static Person createEmployedHomeOwningFemale(
  String newName,StringnewAddress)
  {
  return new Person(
  newName, newAddress,String FEMALE,null,String HOME_OWNER);
  }
 
public static Person createEmployedHomeowningMale(
  String newName,StringnewAddress)
  {
  return new Person(
  newName, newAddress,String MALE, String EMPLOYED,null);
  }
 
public static Person createUnemployedMaleRenter(
  String newName,StringnewAddress)
  {
  return new Person(
  newName, newAddress,null,StringNOT_EMPLOYED, String RENTER);
  }
 
 

如上面的示例代码所示,这些方法具有较高的可读性并且不会要求传入很多参数。最后两个示例结合了方法重载和静态初始化工厂。

 方法命名的好处和优点

相比简单的方法重载,恰如其分地定义描述了所需参数信息的方法名有一些优点。方法名可以根据方法的预期和假设定制,调用方法函数的代码的意图也更加明显。就像上面的示例代码那样,通过方法名可以看出哪些参数不必直接提供,因为它们被设定为方法的一部分(这种意图通过方法名而不是来注释来传达)。

有一个优势在本文并没有明确地说明:相比方法重载,方法名可以包含参数的单位或者其它背景信息。举个例子,可以用接收整数的方法setWholeLengthInMeters(int)和接收小数的方法setFractionalLengthInFeet(double)来代替需要同时接收整数和小数的方法setLength()。

 方法命名的代价和缺点

虽然使用不同名字的方法实例化和静态初始化工厂相比方法重载具有一些明显的优势,但不幸的是方法命名也具有方法重载的一些问题。一个相同的问题是,为了支持可能会用到的参数所有排列组合,需要编写大量的方法。拿上面的例子来说,为包含性别、房屋所有权和工作状况的所有组合方式就需要8个方法(2的3次方)。假设任意一个单独的参数值有2种以上可能,那么为了覆盖参数值的不同组合方法名数量就需要随着参数可能的数量增长。当然,参数值具有无限可能的情况不能用不同的方法名定义所有的可能,只能传递它的值而不是在方法中设定。

虽然描述性的方法名非常易于理解,但是用户在调用方法时可能会需要在长长的方法列表中跋涉。因此,方法命名可能导致由于方法过多而降低整体的可读性。另外,一些人可能不喜欢长长的方法名所据过多的屏幕空间。我个人并不介意长函数名,我认为它们为提高可读性在屏幕上显示额外的文本是值得的。有IDE和语言规范的帮助,基本不会在输入长方法名时出错。为开发者配备多个大屏监控器也使得长方法名的不是那么让人烦恼。

结论

方法名可以用来向用户传递重要信息。在努力净化特定方法的参数个数(包括减少参数个数)时,通过适当的方法命名可以了解方法的默认设置、哪些参数是不需要的,还可以解释其它参数的排列顺序及其特征。

你可能感兴趣的:(静态初始化工厂)