1.建造者(Builder)模式定义
- 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
2.建造者模式主要优缺点
优点:
- 各个具体的建造者相互独立,有利于系统的扩展。
- 客户端不必知道产品内部组成的细节,便于控制细节风险。
缺点:
- 产品的组成部分必须相同,这限制了其使用范围。
- 如果产品的内部变化复杂,该模式会增加很多的建造者类。
建造者模式和工厂模式的关注点不同:
建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程,但两者可以结合使用。
3.建造者模式主要角色
- 产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个滅部件。
- 抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult()。
- 具体建造者(Concrete Builder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。
- 指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。
4.建造者模式结构图
5.建造者模式实现,以建造机器人为例
- 创建机器人模型类。产品角色(Product)
package com.lw.designpattern.builder; /** * @Classname Robot * @Description 机器人模型 * @Author lw * @Date 2019-12-25 08:38 */ public class Robot { /** 头 */ private String head; /** 身体 */ private String body; /** 手 */ private String hand; /** 脚 */ private String foot; public String getHead() { return head; } public void setHead(String head) { this.head = head; } public String getBody() { return body; } public void setBody(String body) { this.body = body; } public String getHand() { return hand; } public void setHand(String hand) { this.hand = hand; } public String getFoot() { return foot; } public void setFoot(String foot) { this.foot = foot; } }
- 创建建造机器人接口。抽象建造者(Builder)
package com.lw.designpattern.builder; /** * @Classname IBuildRobot * @Description 建造机器人接口 * @Author lw * @Date 2019-12-25 08:39 */ public interface IBuildRobot { /** 建造头 */ public void buildHead(); /** 建造身体 */ public void buildBody(); /** 建造手 */ public void buildHand(); /** 建造脚 */ public void buildFoot(); /** 获取机器人结果 */ public Robot getRobotResult(); }
- 创建建造跳舞机器人类,实现IBuildRobot接口。具体建造者(Concrete Builder)
package com.lw.designpattern.builder; /** * @Classname DanceRobotBuilder * @Description 建造跳舞机器人 * @Author lw * @Date 2019-12-25 08:43 */ public class DanceRobotBuilder implements IBuildRobot { private Robot robot; public DanceRobotBuilder(){ robot = new Robot(); } @Override public void buildHead() { robot.setHead("写入机械舞程序"); } @Override public void buildBody() { robot.setBody("钛合金身体"); } @Override public void buildHand() { robot.setHand("钛合金手"); } @Override public void buildFoot() { robot.setFoot("钛合金脚"); } @Override public Robot getRobotResult() { return robot; } }
- 创建指挥官类。指挥者(Director)
package com.lw.designpattern.builder; /** * @Classname Director * @Description 指挥官 * @Author lw * @Date 2019-12-25 08:45 */ public class Director { public Robot createRobotByDirecotr(IBuildRobot ibr){ ibr.buildBody(); ibr.buildFoot(); ibr.buildHand(); ibr.buildHead(); return ibr.getRobotResult(); } }
- 单元测试
/** * 建造者模式 */ @Test public void testBuilder(){ Director director = new Director(); Robot robot = director.createRobotByDirecotr(new DanceRobotBuilder()); System.out.println(robot.getHead()); System.out.println(robot.getBody()); System.out.println(robot.getHand()); System.out.println(robot.getFoot()); System.out.println("机器人创建成功!!!"); }
打印结果
6.建造者模式的应用场景
建造者模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在以下场合使用。
- 创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。
- 创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的。
7.扩展,开源框架Mybatis中建造者模式的应用
- Mybatis中用到的建造者模式:
SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder等。
- 举个读Mybatis源码的例子:
XMLConfigBuilder读取配置文件构建出Configuration对象,然后SqlSessionFactoryBuilder使用Configuration对象作为参数,构建出SqlSessionFactory对象。
- 分析原因
这么做的原因是Mybatis的初始化工作较复杂,不是一个构造函数就能包括的。所以采用了分层构建方法。例如Mybatis中极其重要的Configuration对象,它庞大且复杂,初始化比较麻烦,所以使用专门的建造者XMLConfigBuilder进行构建。