重構--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"; }
- 優點:遇到可選參數或者默認參數時,使用方法重載會十分有效。
-
參考資料