重构--Java方法参数过多
- 示例方法
public void getNews(Context context,
Callback callback,
String uuid,
String uid,
String from,
String token,
String uid,
String .....){
//逻辑
}
- 示例构造函数
public class Person {
public String lastName;
public String firstName;
public String middleName;
public String salutation;
public String suffix;
public String streetAddress;
public String city;
public String state;
public boolean isFemale;
public boolean isEmployed;
public boolean isHomeOwner;
public Person(String lastName, String firstName, String middleName, String salutation,
String suffix, String streetAddress, String city, String state,
boolean isFemale, boolean isEmployed, boolean isHomeOwner) {
this.lastName = lastName;
this.firstName = firstName;
this.middleName = middleName;
this.salutation = salutation;
this.suffix = suffix;
this.streetAddress = streetAddress;
this.city = city;
this.state = state;
this.isFemale = isFemale;
this.isEmployed = isEmployed;
this.isHomeOwner = isHomeOwner;
}
}
- 问题:
添加大量参数理解难度
易参数位置不正确且运行正常
不易维护
-
那一个方法或者构造方法多少个参数才好了--没有答案
- Robert Martin在Clean Code写到
函数参数的理想个数是零,其次是一,紧随其后的是二,应该尽可能避免三个参数的情况。参数如果多于三个则需要特殊的理由,而且无论如何都不应该再使用。
- Steve McConnell在Code Complete中写到:开发者应该限制参数在七个以内
解决方法
- 引入参数对象
- 参数关系紧密合并到一个对象中
- Person.class
- 参数关系紧密合并到一个对象中
public class Person {
public FullName fullName;
public Address address;
public boolean isFemale;
public boolean isEmployed;
public boolean isHomeOwner;
public Person(FullName fullName, Address address, boolean isFemale, boolean isEmployed, boolean isHomeOwner) {
this.fullName = fullName;
this.address = address;
this.isFemale = isFemale;
this.isEmployed = isEmployed;
this.isHomeOwner = isHomeOwner;
}
}
- FullName.class
public class FullName {
public String lastName;
public String firstName;
public String middleName;
public String salutation;
public String suffix;
public FullName(String lastName, String firstName, String middleName, String salutation, String suffix) {
this.lastName = lastName;
this.firstName = firstName;
this.middleName = middleName;
this.salutation = salutation;
this.suffix = suffix;
}
}
- Address.class
public class Address {
public String streetAddress;
public String city;
public String state;
public Address(String streetAddress, String city,
String state) {
this.streetAddress = streetAddress;
this.city = city;
this.state = state;
}
}
- 问题:参数对象可能被滥用。如果一个开发者纯粹为了减少参数数量,把联系不紧的几个参数强捆在一个类中这肯定是行不通的,在可读性上甚至适得其反。
- Builder模式:
- 需求:当一个对象需要不同的参数构造方法?不能写5*5满足所有的需求吧
- 适用范围:构建对象时,如果碰到类有很多参数——其中很多参数类型相同而且很多参数可以为空时,使用Builder模式来完成。当参数数量不多、类型不同而且都是必须出现时,通过增加代码实现Builder往往无法体现它的优势。在这种情况下,理想的方法是调用传统的构造函数。再者,如果不需要保持不变,那么就使用无参构造函数调用相应的set方法吧。
- 代码
- Person.class
public class Person {
public FullName fullName;
public Address address;
public boolean isFemale;
public boolean isEmployed;
public boolean isHomeOwner;
public Person(FullName fullName, Address address, boolean isFemale, boolean isEmployed, boolean isHomeOwner) {
this.fullName = fullName;
this.address = address;
this.isFemale = isFemale;
this.isEmployed = isEmployed;
this.isHomeOwner = isHomeOwner;
}
public static class Builder {
private FullName fullName;
private Address address;
private boolean isFemale;
private boolean isEmployed;
private boolean isHomeOwner;
/**
* 如果有必填参数这里可以构造必填构造方法
*/
public Builder() {
}
public Builder setFullName(FullName fullName) {
this.fullName = fullName;
return this;
}
public Builder setAddress(Address address) {
this.address = address;
return this;
}
public Builder setFemale(boolean female) {
isFemale = female;
return this;
}
public Builder setEmployed(boolean employed) {
isEmployed = employed;
return this;
}
public Builder setHomeOwner(boolean homeOwner) {
isHomeOwner = homeOwner;
return this;
}
public Person create() {
return new Person(fullName, address, isFemale, isEmployed, isHomeOwner);
}
}
}
- FullName.class
public class FullName {
public String lastName;
public String firstName;
public String middleName;
public String salutation;
public String suffix;
public FullName(String lastName, String firstName, String middleName, String salutation, String suffix) {
this.lastName = lastName;
this.firstName = firstName;
this.middleName = middleName;
this.salutation = salutation;
this.suffix = suffix;
}
public static class Builder {
private String lastName;
private String firstName;
private String middleName;
private String salutation;
private String suffix;
public Builder() {
}
public Builder setLastName(String lastName) {
this.lastName = lastName;
return this;
}
public Builder setFirstName(String firstName) {
this.firstName = firstName;
return this;
}
public Builder setMiddleName(String middleName) {
this.middleName = middleName;
return this;
}
public Builder setSalutation(String salutation) {
this.salutation = salutation;
return this;
}
public Builder setSuffix(String suffix) {
this.suffix = suffix;
return this;
}
public FullName create() {
return new FullName(lastName, firstName, middleName, salutation, suffix);
}
}
}
- Address.class
public class Address {
public String streetAddress;
public String city;
public String state;
public Address(String streetAddress, String city, String state) {
this.streetAddress = streetAddress;
this.city = city;
this.state = state;
}
public static class Builder {
private String streetAddress;
private String city;
private String state;
public Builder() {
}
public Builder setStreetAddress(String streetAddress) {
this.streetAddress = streetAddress;
return this;
}
public Builder setCity(String city) {
this.city = city;
return this;
}
public Builder setState(String state) {
this.state = state;
return this;
}
public Address create() {
return new Address(streetAddress, city, state);
}
}
}
调用的地方
public static void main(String[] args) {
FullName fullName = new FullName.Builder().setFirstName("yes")
.setLastName("no").create();
Address address = new Address.Builder().setCity("china").setState("12")
.create();
Person person = new Person.Builder().setAddress(address)
.setFullName(fullName).create();
}
优点:客户端代码的可用性和可读性得到了大大提高,构造函数的参数数量明显减少调用起来非常直观。单个builder构建多个对象时Builder参数可在创建期间进行调整,还可以根据对象不同而进行改变,有效的避免重载构造函数。
缺点:增加代码量,代码变得更加冗长(相比较参数数量的增加,相同类型的参数混在一起,可选参数的增加而言,改善代码可读性更有价值)
-
重载
- 适用范围:方法中参数可选参数或者参数中指定参数相同
- 代码
public String name(String name,int year) { return name+year; } /** * 重载 * @param name * @return */ public String name(String name) { return name+"null"; }
- 优点:遇到可选参数或者默认参数时,使用方法重载会十分有效。
-
参考资料