建造者模式,顾名思义就是要构建某一个产品。但是这个模式与工厂方法模式和抽象工厂模式的侧重点是不同,具体怎么不同,先来看一段例子:假设有一个生产飞机的工厂,每天做的当然是生产飞机零件、组装飞机等一系列的操作,只要收到订单,那么就要开始生产。现在有个奇葩的客户,要求按照他的想法组装飞机;隔断时间又有一个奇葩客户,要求按照他的想法组装飞机,为了满足客户的需求,再苦再难也要搞啊。
下面将这个例子用代码进行实现:
public class Builder_01 {
//飞机抽象类
static abstract class Airplane{
private List<String> sequences;
//组装引擎
protected abstract void assembleEnginee();
//组装机身
protected abstract void assembleBody();
//组装控制台
protected abstract void assembleControl();
//组装武器
protected abstract void assembleWeapon();
public void finish(){
if(null!=this.sequences && this.sequences.size()>0){
for (String sequence : this.sequences) {
switch (sequence.toLowerCase()){
case "enginee": this.assembleEnginee();break;
case "body": this.assembleBody();break;
case "control": this.assembleControl();break;
case "weapon": this.assembleWeapon();break;
default:break;
}
}
}
}
public void setSequences(List<String> sequences){
this.sequences = sequences;
}
}
//歼-7前线机
static class AnnihilatSevenAirplane extends Airplane{
@Override
protected void assembleEnginee() {
System.out.println("组装歼-7前线机引擎");
}
@Override
protected void assembleBody() {
System.out.println("组装歼-7前线机机身");
}
@Override
protected void assembleControl() {
System.out.println("组装歼-7前线机控制台");
}
@Override
protected void assembleWeapon() {
System.out.println("组装歼-7前线机武器");
}
}
//歼-8高空高速截击机
static class AnnihilatEightAirplane extends Airplane{
@Override
protected void assembleEnginee() {
System.out.println("组装歼-8高空高速截击机引擎");
}
@Override
protected void assembleBody() {
System.out.println("组装歼-8高空高速截击机机身");
}
@Override
protected void assembleControl() {
System.out.println("组装歼-8高空高速截击机控制台");
}
@Override
protected void assembleWeapon() {
System.out.println("组装歼-8高空高速截击机武器");
}
}
public static void main(String[] args) {
//开始提供组装顺序
List<String> sequences = new ArrayList<>();
sequences.add("enginee");
sequences.add("body");
sequences.add("control");
sequences.add("weapon");
AnnihilatEightAirplane annihilatEightAirplane = new AnnihilatEightAirplane();
annihilatEightAirplane.setSequences(sequences);
annihilatEightAirplane.finish();
System.out.println("==========================================================");
sequences.clear();
sequences.add("control");
sequences.add("body");
sequences.add("enginee");
sequences.add("weapon");
AnnihilatSevenAirplane annihilatSevenAirplane = new AnnihilatSevenAirplane();
annihilatSevenAirplane.setSequences(sequences);
annihilatSevenAirplane.finish();
}
}
由于每个飞机的主要部件相同,所有抽象出四个方法,分别代表组装不同的部件。同时由于需要根据客户提供的组装顺序进行组装,这里提供一个具体方法(模板方法模式),封装组装步骤,由具体的飞机来实现各自部件组装逻辑。
运行以上代码:
组装歼-8高空高速截击机引擎
组装歼-8高空高速截击机机身
组装歼-8高空高速截击机控制台
组装歼-8高空高速截击机武器
======================================
组装歼-7前线机控制台
组装歼-7前线机机身
组装歼-7前线机引擎
组装歼-7前线机武器
以上就是通过提供的顺序来完成最终的组装,但是观察上面的main方法中的代码,提供了具体的组装命令之后,都是通过new来创建实例,并且接受组装顺序,由于两个具体的飞机都继承自Airplane,这里对其接受操作命令和返回实例做一个抽象封装,并由具体的类来实现:
public class Builder_02 {
//飞机抽象类
static abstract class Airplane{
private List<String> sequences;
//组装引擎
protected abstract void assembleEnginee();
//组装机身
protected abstract void assembleBody();
//组装控制台
protected abstract void assembleControl();
//组装武器
protected abstract void assembleWeapon();
public void finish(){
if(null!=this.sequences && this.sequences.size()>0){
for (String sequence : this.sequences) {
switch (sequence.toLowerCase()){
case "enginee": this.assembleEnginee();break;
case "body": this.assembleBody();break;
case "control": this.assembleControl();break;
case "weapon": this.assembleWeapon();break;
default:break;
}
}
}
}
public void setSequences(List<String> sequences){
this.sequences = sequences;
}
}
//歼-7前线机
static class AnnihilatSevenAirplane extends Airplane{
@Override
protected void assembleEnginee() {
System.out.println("组装歼-7前线机引擎");
}
@Override
protected void assembleBody() {
System.out.println("组装歼-7前线机机身");
}
@Override
protected void assembleControl() {
System.out.println("组装歼-7前线机控制台");
}
@Override
protected void assembleWeapon() {
System.out.println("组装歼-7前线机武器");
}
}
//歼-8高空高速截击机
static class AnnihilatEightAirplane extends Airplane{
@Override
protected void assembleEnginee() {
System.out.println("组装歼-8高空高速截击机引擎");
}
@Override
protected void assembleBody() {
System.out.println("组装歼-8高空高速截击机机身");
}
@Override
protected void assembleControl() {
System.out.println("组装歼-8高空高速截击机控制台");
}
@Override
protected void assembleWeapon() {
System.out.println("组装歼-8高空高速截击机武器");
}
}
//抽象建造者
static abstract class AirplaneBuilder{
public abstract Airplane getAirplane();
public abstract void setSequences(List<String> sequences);
}
//歼-7前线机建造者
static class AnnihilatSevenAirplaneBuilder extends AirplaneBuilder{
private Airplane airplane = new AnnihilatSevenAirplane();
@Override
public Airplane getAirplane() {
return airplane;
}
@Override
public void setSequences(List<String> sequences) {
this.airplane.setSequences(sequences);
}
}
//歼-8高空高速截击机建造者
static class AnnihilatEightAirplaneBuilder extends AirplaneBuilder{
private Airplane airplane = new AnnihilatEightAirplane();
@Override
public Airplane getAirplane() {
return airplane;
}
@Override
public void setSequences(List<String> sequences) {
this.airplane.setSequences(sequences);
}
}
public static void main(String[] args) {
//开始提供组装顺序
List<String> sequences = new ArrayList<>();
sequences.add("enginee");
sequences.add("body");
sequences.add("control");
sequences.add("weapon");
AnnihilatSevenAirplaneBuilder annihilatSevenAirplaneBuilder = new AnnihilatSevenAirplaneBuilder();
annihilatSevenAirplaneBuilder.setSequences(sequences);
annihilatSevenAirplaneBuilder.getAirplane().finish();
System.out.println("==========================================================");
sequences.clear();
sequences.add("control");
sequences.add("body");
sequences.add("enginee");
sequences.add("weapon");
AnnihilatEightAirplaneBuilder annihilatEightAirplaneBuilder = new AnnihilatEightAirplaneBuilder();
annihilatEightAirplaneBuilder.setSequences(sequences);
annihilatEightAirplaneBuilder.getAirplane().finish();
}
}
以上代码抽象了一个建造者类,这个抽象类负责提供具体的飞机类,已经接受组装顺序,需要具体的飞机建造者来实现。这样的改动,看起来跟之前的没多大区别,但实际上就设计而言还是好了很多,毕竟不用每次都手动new一个飞机对象,具体飞机对象的返回由对应的建造者来提供。
从上面两段代码来看,组装的顺序,以及具体的命令都是暴露在外面的,但是对客户来讲,我只需要知道顺序,具体内部命令是怎样的我并不关心,下面我们再抽象一个类来提供组装顺序,这个类由客户来调用,调用不同的方法,对应的就是不同的组装顺序,以及组装命令,看代码:
public class Builder_03 {
//飞机抽象类
static abstract class Airplane{
private List<String> sequences;
//组装引擎
protected abstract void assembleEnginee();
//组装机身
protected abstract void assembleBody();
//组装控制台
protected abstract void assembleControl();
//组装武器
protected abstract void assembleWeapon();
public void finish(){
if(null!=this.sequences && this.sequences.size()>0){
for (String sequence : this.sequences) {
switch (sequence.toLowerCase()){
case "enginee": this.assembleEnginee();break;
case "body": this.assembleBody();break;
case "control": this.assembleControl();break;
case "weapon": this.assembleWeapon();break;
default:break;
}
}
}
}
public void setSequences(List<String> sequences){
this.sequences = sequences;
}
}
//歼-7前线机
static class AnnihilatSevenAirplane extends Airplane{
@Override
protected void assembleEnginee() {
System.out.println("组装歼-7前线机引擎");
}
@Override
protected void assembleBody() {
System.out.println("组装歼-7前线机机身");
}
@Override
protected void assembleControl() {
System.out.println("组装歼-7前线机控制台");
}
@Override
protected void assembleWeapon() {
System.out.println("组装歼-7前线机武器");
}
}
//歼-8高空高速截击机
static class AnnihilatEightAirplane extends Airplane{
@Override
protected void assembleEnginee() {
System.out.println("组装歼-8高空高速截击机引擎");
}
@Override
protected void assembleBody() {
System.out.println("组装歼-8高空高速截击机机身");
}
@Override
protected void assembleControl() {
System.out.println("组装歼-8高空高速截击机控制台");
}
@Override
protected void assembleWeapon() {
System.out.println("组装歼-8高空高速截击机武器");
}
}
//抽象建造者
static abstract class AirplaneBuilder{
public abstract Airplane getAirplane();
public abstract void setSequences(List<String> sequences);
}
//歼-7前线机建造者
static class AnnihilatSevenAirplaneBuilder extends AirplaneBuilder{
private Airplane airplane = new AnnihilatSevenAirplane();
@Override
public Airplane getAirplane() {
return airplane;
}
@Override
public void setSequences(List<String> sequences) {
this.airplane.setSequences(sequences);
}
}
//歼-8高空高速截击机建造者
static class AnnihilatEightAirplaneBuilder extends AirplaneBuilder{
private Airplane airplane = new AnnihilatEightAirplane();
@Override
public Airplane getAirplane() {
return airplane;
}
@Override
public void setSequences(List<String> sequences) {
this.airplane.setSequences(sequences);
}
}
//导演类,封装不同飞机型号的组装顺序
static class Director{
private List<String> sequences = new ArrayList<>();
private Airplane annihilatSevenAirplane = new AnnihilatSevenAirplane();
private Airplane annihilatEightAirplane = new AnnihilatEightAirplane();
public Airplane getABAnnihilatSevenAirplane(){
this.sequences.clear();
sequences.add("enginee");
sequences.add("body");
this.annihilatSevenAirplane.setSequences(sequences);
return annihilatSevenAirplane;
}
public Airplane getCDAnnihilatSevenAirplane(){
this.sequences.clear();
sequences.add("control");
sequences.add("weapon");
this.annihilatSevenAirplane.setSequences(sequences);
return annihilatSevenAirplane;
}
public Airplane getACBDAnnihilatEightAirplane(){
this.sequences.clear();
sequences.add("enginee");
sequences.add("control");
sequences.add("body");
sequences.add("weapon");
this.annihilatEightAirplane.setSequences(sequences);
return annihilatEightAirplane;
}
}
public static void main(String[] args) {
Director director = new Director();
director.getABAnnihilatSevenAirplane().finish();
System.out.println("==========================================================");
director.getACBDAnnihilatEightAirplane().finish();
}
}
以上代码添加了一个Director类,里面仅仅封装了符合客户组装顺序、命令的逻辑,并返回对应的具体飞机类,所以可以将这个类看做命令提供者,客户想指定哪种顺序组装,制度要调用对应的方法,返回对应的飞机类,然后调用finish()方法即可。
如果后续有新的顺序,只需要在这个类里面继续添加新的方法就可以了,其他的类并不需要进行修改。
以上就是建造者模式要做的事情,经过上面一步一步的修改,对建造者模式要做什么大致有一个了解。下面来看看官方的建造者模式的定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
这里面提高了构建过程,也就是我们Airplane类里面封装的finish()方法,这里面就是一个构建过程,只是如何构建是通过外部提供的命令执行顺序来构建的(也就印证了,同样的构建过程可以创建不同的表示)。
总结:
所以建造者模式,跟工厂方法和抽象工厂最大的区别在于:工厂方法和抽象方法主要在于创建对象;而建造者主要在于构建的顺序。
实际应用
参考:构建elasticsearch的restfull查询语句的方式。