说明:本文介绍设计模式中,创建型设计模式中的最后一个,建造者模式;
创建型模式,关注于对象的创建,建造者模式也不例外。假设现在有一个场景,高校开学,学生、教师、职工都要办理相关的报道手续,如签到、个人信息录入、分配身份证明(学生证、教师证、职工证)等等;
首先,创建一个抽象类,如下:
(Person,人员类,有签到、个人信息、身份证明属性)
/**
* 人员
*/
public class Person {
/**
* 签到
*/
private String signIn;
/**
* 个人信息
*/
private String profile;
/**
* 身份证明
*/
private String idCard;
public String getSignIn() {
return signIn;
}
public void setSignIn(String signIn) {
this.signIn = signIn;
}
public String getProfile() {
return profile;
}
public void setProfile(String profile) {
this.profile = profile;
}
public String getIdCard() {
return idCard;
}
public void setIdCard(String idCard) {
this.idCard = idCard;
}
}
在创建具体对象之前,先创建一个抽象的建造者类,用于统一方法,定义人员对象;
(PersonBuilder,人员建造者)
/**
* 抽象建造者
*/
public abstract class PersonBuilder {
Person person = new Person();
/**
* 签到行为
*/
public abstract void buildSignIn();
/**
* 录入个人信息
*/
public abstract void buildProfile();
/**
* 办理身份证明
*/
public abstract void buildIdCard();
/**
* 建造完成
* @return
*/
public Person build() {
return person;
}
}
(Student,学生类,继承人员建造者,重写学生入学相关方法)
/**
* 学生入学
*/
public class Student extends PersonBuilder {
@Override
public void buildSignIn() {
person.setSignIn("学生已签到");
}
@Override
public void buildProfile() {
person.setProfile("学生信息已录入");
}
@Override
public void buildIdCard() {
person.setIdCard("学生证已办理");
}
}
(Teacher,教师类,继承人员建造者,重写教师入学相关方法)
/**
* 教师入学
*/
public class Teacher extends PersonBuilder {
@Override
public void buildSignIn() {
person.setSignIn("老师已签到");
}
@Override
public void buildProfile() {
person.setProfile("老师个人信息已录入");
}
@Override
public void buildIdCard() {
person.setIdCard("老师身份证已办理");
}
}
(Employee,职工类,继承人员建造者,重写职工入学相关方法)
/**
* 职工入学
*/
public class Employee extends PersonBuilder {
@Override
public void buildSignIn() {
person.setSignIn("员工已签到");
}
@Override
public void buildProfile() {
person.setProfile("员工个人信息已录入");
}
@Override
public void buildIdCard() {
person.setIdCard("员工身份证已办理");
}
}
再创建一个建造者控制类,协调入学后的具体事宜,如先签到、后录入个人信息,最后才发身份证明,返回建造完成的人员对象;
(PersonController,人员入学控制器)
/**
* 人员入学控制器
*/
public class PersonController {
/**
* 人员入学
* @return
*/
public Person construct(PersonBuilder personBuilder) {
personBuilder.buildSignIn();
personBuilder.buildProfile();
personBuilder.buildIdCard();
return personBuilder.build();
}
}
(Client,客户端,演示人员入学过程)
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
// 一个学生入学
Person student = new PersonController().construct(new Student());
System.out.println(student.getSignIn());
System.out.println(student.getProfile());
System.out.println(student.getIdCard());
System.out.println("=====================================");
// 一个老师入学
Person teacher = new PersonController().construct(new Teacher());
System.out.println(teacher.getSignIn());
System.out.println(teacher.getProfile());
System.out.println(teacher.getIdCard());
}
}
(执行结果,可见对象已创建完成)
在《设计模式的艺术》(第一版,刘伟著)中,作者关于PersonController(人员控制器)类的作用,有两点改进与优化的地方,如下:
可在抽象建造者类PersonBuilder(人员建造者)中定义一个静态的Person变量,这样就不需要额外设立一个PersonController类了,如下:
(PersonBuilder,抽象人员建造者,既统一了方法,也完成了建造的流程)
/**
* 抽象建造者
*/
public abstract class PersonBuilder {
/**
* 定义一个抽象的Person
*/
protected static Person person = new Person();
/**
* 签到行为
*/
public abstract void buildSignIn();
/**
* 录入个人信息
*/
public abstract void buildProfile();
/**
* 办理身份证明
*/
public abstract void buildIdCard();
/**
* 建造Person
* @return
*/
public static Person build(PersonBuilder personBuilder) {
personBuilder.buildSignIn();
personBuilder.buildProfile();
personBuilder.buildIdCard();
return person;
}
}
(Client,客户端,使用人员建造者的build()方法建造对象)
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
// 一个学生入学
Person student = PersonBuilder.build(new Student());
System.out.println(student.getSignIn());
System.out.println(student.getProfile());
System.out.println(student.getIdCard());
System.out.println("=====================================");
// 一个老师入学
Person teacher = PersonBuilder.build(new Teacher());
System.out.println(teacher.getSignIn());
System.out.println(teacher.getProfile());
System.out.println(teacher.getIdCard());
}
}
(执行效果相同)
可以定义一个“钩子”方法,“钩子”方法一般是“isXXX”命名的,返回值为boolean类型。利用“钩子”方法,规定某些人员可以跳过或者必须执行某方法,来细化对象建造的流程。如规定教师人员的建造,因为教师流动不大,可以跳过录入信息流程。
就可以在PersonBuilder类中定义一个“钩子”方法,默认返回true,即默认所有人员都需要录入个人信息。如下:
/**
* 抽象建造者
*/
public abstract class PersonBuilder {
/**
* 定义一个抽象的Person
*/
protected static Person person = new Person();
/**
* 签到行为
*/
public abstract void buildSignIn();
/**
* 录入个人信息
*/
public abstract void buildProfile();
/**
* 办理身份证明
*/
public abstract void buildIdCard();
/**
* 钩子方法:表示默认所有人都需要经过buildProfile()方法,具体由子类实现
*/
public boolean isBuildProfile() {
return true;
}
/**
* 建造Person
* @return
*/
public static Person build(PersonBuilder personBuilder) {
personBuilder.buildSignIn();
// 根据钩子方法判断是否需要buildProfile()
if (personBuilder.isBuildProfile()) {
personBuilder.buildProfile();
}
personBuilder.buildIdCard();
return person;
}
}
教师类中,可以重写这个“钩子”方法,表示不需要执行录入个人信息这个流程了。
/**
* 教师入学
*/
public class Teacher extends PersonBuilder {
@Override
public void buildSignIn() {
person.setSignIn("老师已签到");
}
@Override
public void buildProfile() {
person.setProfile("老师个人信息已录入");
}
@Override
public void buildIdCard() {
person.setIdCard("老师身份证已办理");
}
@Override
public boolean isBuildProfile() {
return false;
}
}
客户端代码不变,执行
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
// 一个学生入学
Person student = PersonBuilder.build(new Student());
System.out.println(student.getSignIn());
System.out.println(student.getProfile());
System.out.println(student.getIdCard());
System.out.println("=====================================");
// 一个老师入学
Person teacher = PersonBuilder.build(new Teacher());
System.out.println(teacher.getSignIn());
System.out.println(teacher.getProfile());
System.out.println(teacher.getIdCard());
}
}
执行结果可以看到教师确实是没有执行录入个人信息的方法,但是因为Person是static修饰的属性,打印的是上面学生的值。
那么,如果避免这个问题值得思考,或者就不省略PersonController类。
建造者模式,通过定义一个抽象建造者类,封装了对象创建的细节,另外通过“钩子”方法,可细化对象创建过程,降低了系统复杂度,维护了系统的灵活性和扩展性。
本文参考《设计模式的艺术》、《秒懂设计模式》两书