建造器模式
1. 使用场景
当一个对象的构建过程不固定,需要根据各种条件生成最后对象时
2. 体现举例
字符串处理
在多条件SQL组合查询中经常可见建造器的身影:
public static String buildSQL(String name, Integer age, Date birthday) {
StringBuilder sb = new StringBuilder(256);
sb.append("select * from t_user where 1=1");
if (name != null && !name.equals("")) {
sb.append(" and name=?");
}
if (age != null) {
sb.append(" and age=?");
}
if (birthday != null) {
sb.append(" and birthday=?");
}
return sb.toString();
}
public static void main(String[] args) {
System.out.println(buildSQL("张三", null, null));
// 输出: select * from t_user where 1=1 and name=?
System.out.println(buildSQL(null, 18, null));
// 输出: select * from t_user where 1=1 and age=?
System.out.println(buildSQL("张三", 18, null));
// 输出: select * from t_user where 1=1 and name=? and age=?
System.out.println(buildSQL("张三", 18, new Date()));
// 输出: select * from t_user where 1=1 and name=? and age=? and birthday=?
}
要点
其中
StringBuilder
实现了建造器模式:StringBuilder
根据各个条件是否存在构建最后的String对象
日期处理
import java.time.LocalDate;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.time.temporal.ChronoField;
import java.util.Locale;
public class Test5 {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2017, 2, 19);
System.out.println(date.format(new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR_OF_ERA)
.appendLiteral("年")
.appendValue(ChronoField.MONTH_OF_YEAR, 2)
.appendLiteral("月")
.appendValue(ChronoField.DAY_OF_MONTH)
.appendLiteral("日")
.toFormatter(Locale.CHINA)));
// 输出: 2017年02月19日
System.out.println(date.format(new DateTimeFormatterBuilder()
.appendText(ChronoField.MONTH_OF_YEAR, TextStyle.FULL)
.appendLiteral(" ")
.appendValue(ChronoField.DAY_OF_MONTH)
.appendLiteral(", ")
.appendValue(ChronoField.YEAR_OF_ERA)
.toFormatter(Locale.ENGLISH)));
// 输出: February 19, 2017
}
}
要点
其中
DateTimeFormatterBuilder
实现了建造器模式,因为日期的格式多种多样,构造DateTimeFormatter对象
需要非常灵活,所以DateTimeFormatterBuilder
提供了一系列append方法来完成各种格式控制,最后toFormatter方法生成DateTimeFormatter对象
构建Query对象
在Hibernate查询时,会用到Query对象,类似的,Query对象需要的HQL语句多种多样,并且每条HQL语句需要设置的参数,是否需要分页都不确定。因此Hibernate也是采用了建造器模式来创建Query对象:
import java.util.List;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
@Autowired
private SessionFactory sf;
public List<User> findByName(String name){
Query q = sf.getCurrentSession()
.createQuery("from User where name = ?")
.setString(0, name);
return q.list();
}
public List<User> findByNameAndAge(String name, int age){
Query q = sf.getCurrentSession()
.createQuery("from User where name = ? and age = ?")
.setString(0, name)
.setInteger(1, age);
return q.list();
}
public List<User> findByPage(int page, int size){
Query q = sf.getCurrentSession()
.createQuery("from User")
.setFirstResult((page-1)*size)
.setMaxResults(size);
return q.list();
}
}
要点
其中
createQuery()
,setXXX()
等方法均体现了建造器模式,通过设置不同的条件来创建最终的Query对象。与前面两个例子不同之处在于,没有抽取独立的Builder类