建造者模式,在一些框架中,常和工厂模式一起使用,所以这里对于以后的框架的理解非常重要,所以这里学习一下
建造者模式
1. 场景
我们要建造一个复杂的产品。比如:神舟飞船,IPhone。这个复杂的产品的创建(比如iPhone),有这样问题需要处理:
- iPhone的拼装,需要很多小的组件。也就是说我们除了要构建这些小的组件,比如说电池,固定机身的螺丝钉等,我们还需要装配这些零件,这又是另一个步骤。
- 再比如我们的神舟飞船,我们除了需要生产零件的厂商将零件送过来,我们还需要在一个地方将这些零件按照步骤装配起来。
- 注意,实际开发中,建造者模式一般会和工厂模式搭配起来使用。因为你要建某个零件,这些零件来自于工厂(工厂模式),建造者调用工厂建好这些零件,然后拿过来装配。所以,这些模式经常互相搭配。
实际开发中,建造者模式通常用来构建复杂的对象。说白了也就是建造者类负责对象的创建和返回,返回的对象由组建者进行拼装。
2. 建造者模式的本质
-
分离了对象子组件单独构建(由 Builder 来负责)和装配(由 Director 负责)。从而可以构造出复杂的对象。这个模式适用于:某个对象的构建过程复杂的情况下使用。
-
由于实现了构建和装配的解耦。不同的构建器,相同的装配,可以做出不同的对象;相同的构建器,不同的装配顺序也可以做出不同的对象。也就是实现了构建算法、装配算的解耦,实现了更好的复用。
- 比如之前的造汽车,低级的轮胎,低级的底盘,低级的发动机等等,通过汽车装配,可以产出一辆低端汽车;同样的,我们使用高级的轮胎,高级的底盘,高级的发动机等等,通过汽车装配,我们可以产出一辆高级的汽车。这个就是不同的构建器,相同的装配产出不同的对象。
- 反过来,相同的构建起,不同的装配顺序也可以做出不同的对象。比如搭积木,构建的时候构建了一个矩形,一个小圈。不同的组装顺序出来的结构不一样。比如小圈贴着矩形的宽和小圆贴着矩形的长。
3. 例子
3.1 类的类图 - 创建飞船:
一个飞船类,里面有三个方法:轨道舱,引擎,逃逸塔。一个飞船有这样三个零件。
有这样的一个借口:ArishipBuilder 用来构建我们的各个组件。
还有一个 Director 类,负责装配。在后面的代码实现中,我们将其搞成接口,并创建实现类。这样的就有不同的装配者了。它负责调用 Builder 中的内容,然后再进行组装。最后组装出来一个新的产品。
在后来的调用中,客户端 Client 调用特定的装配者,告诉程序我们要组装一个什么样的产品。然后装配者和建造者打交道,建造者负责调用构造者生产零件,然后装配者负责装配。所以客户端只需要和建造者打交道,其他的在后台由建造者去和其他的类和接口进行沟通。
建造者内部的方法还可以调用工厂模式,从工厂中取出零件,这样就和工厂模式搭配起来了。
3.2 代码的实现
-
首先创建我们的实体类 - AirShip 类,在它之下有它需要的组件:
/** * 宇宙飞船 */ public class AirShip { private OrbitalModule obritalModule; // 轨道舱发 private Engine engine; // 发动机 private EscapeTower escapeTower; // 逃逸仓 public OrbitalModule getObritalModule() { return obritalModule; } public void setObritalModule(OrbitalModule obritalModule) { this.obritalModule = obritalModule; } public Engine getEngine() { return engine; } public void setEngine(Engine engine) { this.engine = engine; } public EscapeTower getEscapeTower() { return escapeTower; } public void setEscapeTower(EscapeTower escapeTower) { this.escapeTower = escapeTower; } public void launch() { System.out.println("发射"); } } class OrbitalModule { private String name; public OrbitalModule(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class Engine { private String name; public Engine(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class EscapeTower { private String name; public EscapeTower(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
-
然后创建建造者接口,用于规范后面的实现类:
public interface AirShipBuilder { Engine builderEngine(); OrbitalModule buildOrbitalModule(); EscapeTower escapeTower(); }
它里面有三个方法,分别是建造引擎,轨道舱和逃逸塔
-
然后创建我们的组装者接口,用于规范后面的组装者的实现类:
public interface AirShipDirector { /** * 组装飞船 * @return AirShip */ AirShip directorAirShip(); }
它就一个方法,组装我们的飞船。
-
然后创建建造者的实现类,SxtAirShipBuilder类:
// StringBuilder, DomBuild, DOMBuilder, SaxBuilder 都是这个模式 public class SxtAirShipBuilder implements AirShipBuilder { @Override public Engine builderEngine() { System.out.println("构建发动机"); return new Engine("发动机"); } @Override public OrbitalModule buildOrbitalModule() { System.out.println("构建轨道舱"); return new OrbitalModule("轨道舱"); } @Override public EscapeTower escapeTower() { System.out.println("构建逃逸塔"); return new EscapeTower("逃逸塔"); } }
这个类我们通过调用不同的构建者,构建不同的对象,然后返回,供组装者组装调用。
-
然后创建我们的组装者类,SxtAirShipDirector类:
public class SxtAirShipDirector implements AirShipDirector { private AirShipBuilder builder; public SxtAirShipDirector(AirShipBuilder builder) { this.builder = builder; } @Override public AirShip directorAirShip() { Engine engine = builder.builderEngine(); OrbitalModule orbitalModule = builder.buildOrbitalModule(); EscapeTower escapeTower = builder.escapeTower(); // 进行组装 AirShip ship = new AirShip(); ship.setEngine(engine); ship.setObritalModule(orbitalModule); ship.setEscapeTower(escapeTower); return ship; } }
组装者内部创建一个建造者对象,用于调用建造者去建造组件,以供自己的组件产品使用。
-
最后,就是我们的客户端类了。
public class Client { public static void main(String[] args) { AirShipDirector airShipDirector = new SxtAirShipDirector(new SxtAirShipBuilder()); AirShip airShip = airShipDirector.directorAirShip(); System.out.println(airShip.getEngine().getName()); airShip.launch(); } }
我们的客户端类只需要和 Director的实现类打交道就可以了。
4. 建造者模式开发的应用场景
- 开发中的应用场景:
- StringBuilder 类的 append 方法
- SQL中的 PreparedStatement 方法
- JDOM 中, DomBuilder、SAXBuilder
- 当然我们在自己开发项目的时候,用到建造者模式的情况并不多见。除非去开发一个产品,这是有可能的。