最近我看到一些开发人员使用嵌套的构建器类(如
)编写他们的VO<form method="post">
<select name="XStocLa" id="StocLa">
<option>A</option>
<option>B</option>
</select>
<input type="submit" value="Select">
</form>
<form method="post">
<input type="date" name="ordersmonth">
<input type="submit" value="Select">
</form>
<?php
if(isset($_POST['ordersmonth'])) {
$OrdersMonth = $_POST['ordersmonth'];
$sql ="SELECT * FROM " .$OrderTable. " WHERE YEAR(Date) = YEAR('" .$OrdersMonth. "') AND MONTH(DATE) = MONTH('" .$OrdersMonth. "') AND StocLa = '$XStocLa' ORDER BY Date DESC, ID ASC";
$result = $conn->query($sql);
} else {
$sql ="SELECT * FROM " .$OrderTable. " WHERE StocLa = '$XStocLa' ORDER BY Date DESC, ID ASC";
$result = $conn->query($sql);
}
?>
现在,他们声称这使代码更具可读性。我的观点是,这有以下缺点:
我不能简单地添加字段并期望我的IDE为我完成代码,因为现在我也需要更新这个内部类。
简单的POJO携带的代码与VO无关。
如果我在这里遗漏了什么,我正在寻找任何建议。随意添加您的想法。
此修改后的示例代码如下所示:
public class User {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public static class UserBuilder {
private String firstName;
private String lastName;
public User build() {
User user = new User();
user.firstName = firstName;
user.lastName = lastName;
return user;
}
public UserBuilder withFirstName(String firstName) {
this.firstName = firstName;
return this;
}
public UserBuilder withLastName(String lastName) {
this.firstName = firstName;
return this;
}
}
}
答案 0 :(得分:1)
以下是约书亚布洛赫的文章。他非常清楚地解释了为什么,何时以及如何使用构建器:http://www.informit.com/articles/article.aspx?p=1216151&seqNum=2
这是他的书“Effective Java”中的一个项目。如果您对Java有一点经验,我强烈建议您阅读本书。
要点:
当你得到一个具有很多属性的类时,有几种方法可以创建一个对象并初始化它。
如果你逐个设置每个属性,它可以是罗嗦的,你的对象可以在创建后改变。使用此方法,不可能使您的类不可变,并且您无法确定您的对象是否处于一致状态。
例子来自文章:
public class NutritionFacts {
// Parameters initialized to default values (if any)
private int servingSize = -1; // Required; no default value
private int servings = -1; // " " " "
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0;
public NutritionFacts() { }
// Setters
public void setServingSize(int val) { servingSize = val; }
public void setServings(int val) { servings = val; }
public void setCalories(int val) { calories = val; }
public void setFat(int val) { fat = val; }
public void setSodium(int val) { sodium = val; }
public void setCarbohydrate(int val) { carbohydrate = val; }
}
您可以使用伸缩构造函数。它可以使您的对象不可变。但是,如果您获得许多属性,则可能很难编写和读取代码。当你只想要使用一个setted属性创建,而不幸的是这个是构造函数的最后一个参数时,你必须设置所有参数。
例子来自文章:
public class NutritionFacts {
private final int servingSize; // (mL) required
private final int servings; // (per container) required
private final int calories; // optional
private final int fat; // (g) optional
private final int sodium; // (mg) optional
private final int carbohydrate; // (g) optional
public NutritionFacts(int servingSize, int servings) {
this(servingSize, servings, 0);
}
public NutritionFacts(int servingSize, int servings,
int calories) {
this(servingSize, servings, calories, 0);
}
public NutritionFacts(int servingSize, int servings,
int calories, int fat) {
this(servingSize, servings, calories, fat, 0);
}
public NutritionFacts(int servingSize, int servings,
int calories, int fat, int sodium) {
this(servingSize, servings, calories, fat, sodium, 0);
}
public NutritionFacts(int servingSize, int servings,
int calories, int fat, int sodium, int carbohydrate) {
this.servingSize = servingSize;
this.servings = servings;
this.calories = calories;
this.fat = fat;
this.sodium = sodium;
this.carbohydrate = carbohydrate;
}
}
构建器允许使代码更易读,更容易编写。它还允许您使您的类不可变。
例子来自文章:
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public static class Builder {
// Required parameters
private final int servingSize;
private final int servings;
// Optional parameters - initialized to default values
private int calories = 0;
private int fat = 0;
private int carbohydrate = 0;
private int sodium = 0;
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val)
{ calories = val; return this; }
public Builder fat(int val)
{ fat = val; return this; }
public Builder carbohydrate(int val)
{ carbohydrate = val; return this; }
public Builder sodium(int val)
{ sodium = val; return this; }
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
}
在您的示例中,我不确定为仅具有两个属性的类执行构建器非常有用。
我希望这会对你有所帮助。
答案 1 :(得分:0)
在给定示例中,恕我直言通过使用Builder模式没有获得任何价值。您可以在没有Builder的情况下创建User
对象(因为所有的setter)。在这种特殊情况下,Builder为您提供的唯一内容是Fluent Interface。
当存在创建有效对象的各种组合时,您应该使用Builder Pattern。多亏了这一点,您将不必实现许多构造函数或工厂方法。
创建有效对象时,构建器也很有用,需要很多参数。
Builder应该负责只构建一个有效的对象。在您的情况下,如果用户需要姓名,则Builder不应该允许创建没有设置这些属性的User实例。
答案 2 :(得分:0)
如果您需要所有属性,那么您应该只使用构造函数。通过这样做,您可以创建漂亮的小型不可变对象。
如果有多个可选字段和不同的方法来创建对象,则需要多个构造函数。
public User (int requiredParameter) { ... }
public User (int reqiredParameter, int optionalParameter) { ... }
public User (int reqiredParameter, int optionalParameter, String optionalParameter2) { ... }
public User (int reqiredParameter, String optionalParameter2) { ... }
它会产生混乱的代码。很难确定应该使用哪个构造函数。 在这种情况下,您可以使用嵌套构建器以直观的方式创建对象。