【设计模式-2.5】创建型——建造者模式

说明:本文介绍设计模式中,创建型设计模式中的最后一个,建造者模式;

入学报道

创建型模式,关注于对象的创建,建造者模式也不例外。假设现在有一个场景,高校开学,学生、教师、职工都要办理相关的报道手续,如签到、个人信息录入、分配身份证明(学生证、教师证、职工证)等等;

首先,创建一个抽象类,如下:

(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());
    }
}

(执行结果,可见对象已创建完成)

【设计模式-2.5】创建型——建造者模式_第1张图片

改进与优化

在《设计模式的艺术》(第一版,刘伟著)中,作者关于PersonController(人员控制器)类的作用,有两点改进与优化的地方,如下:

改进:可省略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());
    }
}

(执行效果相同)

【设计模式-2.5】创建型——建造者模式_第2张图片

优化:细化建造过程

可以定义一个“钩子”方法,“钩子”方法一般是“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修饰的属性,打印的是上面学生的值。

【设计模式-2.5】创建型——建造者模式_第3张图片

那么,如果避免这个问题值得思考,或者就不省略PersonController类。

小结

建造者模式,通过定义一个抽象建造者类,封装了对象创建的细节,另外通过“钩子”方法,可细化对象创建过程,降低了系统复杂度,维护了系统的灵活性和扩展性。

总结

本文参考《设计模式的艺术》、《秒懂设计模式》两书

你可能感兴趣的:(设计模式,建造者模式,java)