java设计模式之Builder模式
最近开始看起了java中的定时任务调度工具Quartz,什么都不懂的我看到一段”诡异的”代码,于是便有了这一篇东东。
引入
- 背景:在Quartz中创建一个JobDetail对象的一段代码
JobDetail jobDetail = JobBuilder.newJob(MyJob.class).withIdentity("my Job", "group1").build();
。本人孤陋寡闻,看到这种创建对象的方法第一反应是Factory、Generator之类,但是再看这不什么都不是啊!但是不难看出它其实就是要创建一个对象,而后面一大串的只是创建前传递的一些参数。 - 于是看了一下JobDetail源码:
public class JobBuilder {
private JobKey key;
private String description;
private Class<? extends Job> jobClass;
private boolean durability;
private boolean shouldRecover;
private JobDataMap jobDataMap = new JobDataMap();
protected JobBuilder() {
}
public static JobBuilder newJob() {
return new JobBuilder();
}
public static JobBuilder newJob(Class<? extends Job> jobClass) {
JobBuilder b = new JobBuilder();
b.ofType(jobClass);
return b;
}
public JobDetail build() {
JobDetailImpl job = new JobDetailImpl();
job.setJobClass(this.jobClass);
job.setDescription(this.description);
if (this.key == null) {
this.key = new JobKey(Key.createUniqueName((String)null), (String)null);
}
job.setKey(this.key);
job.setDurability(this.durability);
job.setRequestsRecovery(this.shouldRecover);
if (!this.jobDataMap.isEmpty()) {
job.setJobDataMap(this.jobDataMap);
}
return job;
}
public JobBuilder withIdentity(String name) {
this.key = new JobKey(name, (String)null);
return this;
}
public JobBuilder withIdentity(String name, String group) {
this.key = new JobKey(name, group);
return this;
}
public JobBuilder withIdentity(JobKey jobKey) {
this.key = jobKey;
return this;
}
public JobBuilder withDescription(String jobDescription) {
this.description = jobDescription;
return this;
}
public JobBuilder ofType(Class<? extends Job> jobClazz) {
this.jobClass = jobClazz;
return this;
}
public JobBuilder requestRecovery() {
this.shouldRecover = true;
return this;
}
public JobBuilder requestRecovery(boolean jobShouldRecover) {
this.shouldRecover = jobShouldRecover;
return this;
}
public JobBuilder storeDurably() {
this.durability = true;
return this;
}
public JobBuilder storeDurably(boolean jobDurability) {
this.durability = jobDurability;
return this;
}
public JobBuilder usingJobData(String dataKey, String value) {
this.jobDataMap.put(dataKey, value);
return this;
}
public JobBuilder usingJobData(String dataKey, Integer value) {
this.jobDataMap.put(dataKey, value);
return this;
}
public JobBuilder usingJobData(String dataKey, Long value) {
this.jobDataMap.put(dataKey, value);
return this;
}
public JobBuilder usingJobData(String dataKey, Float value) {
this.jobDataMap.put(dataKey, value);
return this;
}
public JobBuilder usingJobData(String dataKey, Double value) {
this.jobDataMap.put(dataKey, value);
return this;
}
public JobBuilder usingJobData(String dataKey, Boolean value) {
this.jobDataMap.put(dataKey, value);
return this;
}
public JobBuilder usingJobData(JobDataMap newJobDataMap) {
this.jobDataMap.putAll(newJobDataMap);
return this;
}
public JobBuilder setJobData(JobDataMap newJobDataMap) {
this.jobDataMap = newJobDataMap;
return this;
}
}
可以留意到如下信息:
①构造函数是protected的,说明无法实例化这个类,必须通过其它方式。
②有两个获得JobBuilder实例的方法,只是一个是返回默认的JobBuilder,另一个传递泛化的Class对象。
③JobBuilder有多个以介词开头的方法,这些方法实际上作用就是传来参数并初始化JobBuilder的私有成员,有意思的是返回值是类本身即JobBuilder,说明可以多次重复运用点操作符连续调用这些方法已达到初始化的目的。(这就可以联想到c++中经常用的形如cout << "hello " << name
,也是连续使用”<<”,这也可以说明对应类中的友元函数应该长这个样子friend std::ostream & operator<<(std::ostream & os, const XXX & obj)
,每调用一次就是返回ostream对象本身,所以才可以连续使用)
④但是不要忘记,我们的目的是获得一个JobDetail对象,那么怎么获得呢?答案就在build方法。可以看到它返回一个JobDetail实例(实例上JobDetail是一个接口,而返回的实际上是实现了这个接口的JobDetailImpl对象,并且进一步查看,发现JobDetailImpl的私有成员有大部分都重复出现在JobBuilder类的私有域中),在返回前使用了大量的set方法,将JobBuilder中的私有成员的值赋给JobDetail(Impl)。理解了上面的东西,应该也可以模仿这种方法写一个类似的自己的Builder,但是为什么要用这种方式呢?网上一查,大致是这样解释:
①如果一个类有十分多个成员,而初始化的方法多种多样,编写多个带特定参数的构造函数来满足需求不是不可以,但是不够灵活,难道有一百种构造的方案就写对应的一百种不同参数的构造函数吗?针对这个问题,使用Builder模式直接自己搭配,使用dot操作符连接,直接简单。
②也可以使用默认的构造函数,然后再调用对应的setter方法,其实我觉得完全可行,只是是在构造完对象之后再赋值罢了。缺点,除了要为你的类设置相对应的setter和getter方法外,还要编写它的Builder类,这个Builder类的私有成员其实和你的类中的私有成员是一样的,但是你还要为他们设置相应的赋值方法(例如上面的usingXXX, withXXX等等),增加了代码量。