3.4 建造者模式
定义:建造者模式(Builder Pattern)又叫生成器模式,实际开发中,我们所需要的对象构建时非常复杂,且有很多步骤需要处理时,这时建造者模式就很适合。比如MyBatis中的SqlSessionFactory对象的创建,我们不光要创建SqlSessionFactory本身的对象,还有完成MyBatis的全局配置文件和映射文件的加载解析操作,之后把解析出来的信息绑定在SqlSessionFactory对象中
参考MyBatis的代码
优点:
- 封装性好,创建和使用分离;
- 扩展性好,建造类之间独立、一定程度上解耦。
问题: - 产生多余的Builder对象;
- 产品内部发生变化,建造者都要修改,成本较大。
3.4.1 角色:
- builder(抽象建造者):为创建一个产品对象的各个部件指定抽象接口。
- ConcreteBuilder(具体的建造者):实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并提供一个检索产品的接口。
- Director(指挥者):构造一个使用Builder接口的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。
- Product(产品类):表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
3.4.2 使用场景
- 产品类非常的复杂,或者产品类中的调用顺序不同产生了不同的效能
- 多个部件或者零件,都可以装配到一个对象中,但是产生的结果又不相同
- 当时初始化一个对象特别复杂,参数多,而且很多参数都具有默认值时
- 在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到(需要多行代码)。
3.3.3 代码实现
/**
* @Description 学习抽象类 (产品类)
* @Auther 九止
* Date 2022/10/3 16:46
*/
public abstract class Study {
/**
* 学习顺序参数
*/
private ArrayList<String> sequence = new ArrayList<>();
/**
* 看书学习
*/
public abstract void studyByBook();
/**
* 看视频学习
*/
public abstract void studyByVideo();
/**
* 刷题
*/
public abstract void brushQuestion();
/**
* 复习
*/
public abstract void review();
/**
* 执行学习计划
*/
final public void execute() {
this.sequence.forEach(item->{
switch(item)
{
case "studyByBook":
this.studyByBook();
break;
case "studyByVideo":
this.studyByVideo();
break;
case "brushQuestion":
this.brushQuestion();
break;
case "review":
this.review();
break;
default:
throw new RuntimeException("提示:学习计划有误!");
}
});
}
public ArrayList<String> getSequence() {
return sequence;
}
public void setSequence(ArrayList<String> sequence) {
this.sequence = sequence;
}
}
//=============================================================================
/**
* @Description 英语学习类 (产品类)
* @Auther 九止
* Date 2022/10/3 17:01
*/
public class EnglishStudy extends Study{
@Override
public void studyByBook() {
System.out.println("开始通过看书学习英语……");
}
@Override
public void studyByVideo() {
System.out.println("开始通过看视频学习英语……");
}
@Override
public void brushQuestion() {
System.out.println("开始通过刷题学习英语……");
}
@Override
public void review() {
System.out.println("开始通过复习学习英语……");
}
}
//=============================================================================
/**
* @Description 数学学习类 (产品类)
* @Auther 九止
* Date 2022/10/3 17:01
*/
public class MathStudy extends Study{
@Override
public void studyByBook() {
System.out.println("开始通过看书学习数学……");
}
@Override
public void studyByVideo() {
System.out.println("开始通过看视频学习数学……");
}
@Override
public void brushQuestion() {
System.out.println("开始通过刷题学习数学……");
}
@Override
public void review() {
System.out.println("开始通过复习学习数学……");
}
}
/**
* @Description 学习计划抽象建造者 (抽象建造者) 在该类中提供设置产品类各个属性的方法
* @Auther 九止
* Date 2022/10/3 16:29
*/
public interface StudyPlanBuilder{
/**
* 设置学习顺序
* @param sequence
*/
void setSequence(ArrayList<String> sequence);
/**
* 获取学习对象
* @return
*/
Study getStudy();
}
//=============================================================================
/**
* @Description 英语学习计划建造者
* @Auther 九止
* Date 2022/10/3 17:04
*/
public class EnglishStudyPlanBuilder implements StudyPlanBuilder{
private EnglishStudy englishStudy = new EnglishStudy();
@Override
public void setSequence(ArrayList<String> sequence) {
englishStudy.setSequence(sequence);
}
@Override
public Study getStudy() {
return this.englishStudy;
}
}
//=============================================================================
/**
* @Description 数学学习计划建造者
* @Auther 九止
* Date 2022/10/3 17:04
*/
public class MathStudyPlanBuilder implements StudyPlanBuilder{
private MathStudy mathStudy = new MathStudy();
@Override
public void setSequence(ArrayList<String> sequence) {
mathStudy.setSequence(sequence);
}
@Override
public Study getStudy() {
return this.mathStudy;
}
}
/**
* @Description 学生类充当指挥者的角色 (指挥者)
* @Auther 九止
* Date 2022/10/3 17:13
*/
public class Student {
private final ArrayList<String> sequence = new ArrayList<>();
private final EnglishStudyPlanBuilder englishStudyPlanBuilder = new EnglishStudyPlanBuilder();
private final MathStudyPlanBuilder mathStudyPlanBuilder = new MathStudyPlanBuilder();
private static final String STUDY_BY_BOOK = "studyByBook";
private static final String REVIEW = "review";
private static final String STUDY_BY_VIDEO = "studyByVideo";
private static final String BRUSH_QUESTION = "brushQuestion";
/**
* 英语学习计划A
*/
public EnglishStudy englishPlanA() {
this.sequence.clear();
this.sequence.add(STUDY_BY_BOOK);
this.sequence.add(REVIEW);
this.sequence.add(STUDY_BY_VIDEO);
this.sequence.add(BRUSH_QUESTION);
this.englishStudyPlanBuilder.setSequence(this.sequence);
return (EnglishStudy) this.englishStudyPlanBuilder.getStudy();
}
/**
* 英语学习计划B
*/
public EnglishStudy englishPlanB() {
this.sequence.clear();
this.sequence.add(STUDY_BY_BOOK);
this.sequence.add(STUDY_BY_VIDEO);
this.sequence.add(BRUSH_QUESTION);
this.sequence.add(REVIEW);
this.englishStudyPlanBuilder.setSequence(this.sequence);
return (EnglishStudy) this.englishStudyPlanBuilder.getStudy();
}
/**
* 数学学习计划A
*/
public MathStudy mathPlanA() {
this.sequence.clear();
this.sequence.add(STUDY_BY_BOOK);
this.sequence.add(REVIEW);
this.sequence.add(STUDY_BY_VIDEO);
this.sequence.add(BRUSH_QUESTION);
this.mathStudyPlanBuilder.setSequence(this.sequence);
return (MathStudy) this.mathStudyPlanBuilder.getStudy();
}
/**
* 数学学习计划B
*/
public MathStudy mathPlanB() {
this.sequence.clear();
this.sequence.add(STUDY_BY_BOOK);
this.sequence.add(STUDY_BY_VIDEO);
this.sequence.add(BRUSH_QUESTION);
this.sequence.add(REVIEW);
this.mathStudyPlanBuilder.setSequence(this.sequence);
return (MathStudy) this.mathStudyPlanBuilder.getStudy();
}
}
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.mathPlanA().execute();
System.out.println("-------------------------");
student.englishPlanB().execute();
}
}
3.4.4 与工厂模式对比
- 建造者模式更加注重方法的调用顺序,工厂模式注重于创建对象。
- 杂的部件组成,工厂模式创建出来的都一样。
- 关注点不一样,工厂模式只需要把对象创建出来就行了,而建造者模式不仅要创建出这个对象,还要知道这个对象由哪些部分组成。
- 建造者模式根据建造过程中的顺序不一样,最终的对象部件组成也不一样。
引用了马士兵邓澎波老师笔记的部分原文