@

最近在看Mybatis的源码, 在阅读解析 XML 配置文件的过程中, 发现使用到了建造者(Builder)模式。 因此, 打算重温一下该设计模式。

由来

假设我们需要画一个小人, 我们可能会有以下的构造函数定义:

public Person(HeadType headType, HairType hairType, HairColor hairColor, FaceType faceType, BodyType bodyType, ArmType amrType, LegType legTyype) {
}

看到这么一个构造函数, 估计我们自己以后回来看的时候都懵了, 这么多参数, 导致我们后续的维护也很麻烦。

而构造模式就可以解决此类的问题。

使用

目标是画一个小人

1. 定义抽象 Builder

先定义抽象的PersonBuilder。 该类定义了画小人需要的步骤, 这样每个通过PersonBuilder产生的对象本质上就都是一样的了, 只不过个性上可以不一样。

abstract class PersonBuilder {
protected Graphics graphics; public PersonBuilder(Graphics graphics) {
this.graphics = graphics;
} public abstract void buildHead();
public abstract void buildBody();
public abstract void buildArmLeft();
public abstract void buildArmRight();
public abstract void buildLegLeft();
public abstract void buildLegRight();
}

2. 定义具体 Builder

在定义一个具体的实现类PersonFatBuilder。 该类继承PersonBuilder, 并实现了抽象方法。

public class PersonFatBuilder extends PersonBuilder {
public PersonFatBuilder(Graphics graphics) {
super(graphics);
}
@Override
public void buildHead() {
graphics.drawOval(50, 20, 30, 30);
graphics.drawArc(50, 30, 10, 5, 45, 135);
graphics.drawArc(70, 30, 10, 5, 45, 135);
graphics.drawArc(60, 35, 10, 5, 200, 135);
} @Override
public void buildBody() {
graphics.drawRect(55, 50, 20, 50);
} @Override
public void buildArmLeft() {
graphics.drawLine(55, 50, 40, 100);
} @Override
public void buildArmRight() {
graphics.drawLine(75, 50, 90, 100);
} @Override
public void buildLegLeft() {
graphics.drawLine(55, 100, 45, 150);
} @Override
public void buildLegRight() {
graphics.drawLine(75, 100, 85, 150);
}
}

3. 定义具体 Director

该类负责具体的建造过程, 对建成什么样不关心。

public class PersonDirector {
private PersonBuilder personBuilder; public PersonDirector(PersonBuilder personBuilder) {
this.personBuilder = personBuilder;
} public void drawPerson() {
personBuilder.buildHead();
personBuilder.buildBody();
personBuilder.buildArmLeft();
personBuilder.buildArmRight();
personBuilder.buildLegLeft();
personBuilder.buildLegRight();
}
}

4. 测试

建立一个窗口,将小人画出来。

 public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
// 创建窗口对象
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setTitle("画人");
frame.setSize(250, 300); // 设置窗口关闭按钮的默认操作(点击关闭时退出进程)
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // 把窗口位置设置到屏幕的中心
frame.setLocationRelativeTo(null);
frame.setContentPane(new JPanel(){
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
PersonThinBuilder thinBuilder = new PersonThinBuilder(g);
PersonDirector director = new PersonDirector(thinBuilder);
director.drawPerson(); }
});
}
});
}

结果如下:

定义

文字定义

将复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示。

换句话解释, 允许你创建不同种类的对象, 同时又能避免对构造函数的污染。当对象有多种类型时, 该模式非常有用。 或者在创建对象时涉及到很多的步骤。

结构图

引用《大话设计模式》的一个图

抽象类Builder:为创建Product对象而抽象的接口。

继承类ConcreateBuilder:具体的建造者, 构造和装配各个部件。

具体产品类Product:我们需要建造的对象。

Director: 用来创建产品的, 其内部有Builder类型的成员变量。

优点

  1. Director 不需要知道 Product 的内部细节, 它只提供需要的信息给建设者, 由具体的建造者ConcreateBuilder处理从而完成产品的构造。
  2. 建造者模式将复杂的产品创建过程分散到了不同的对象中, 从而实现对产品创建过程更精确的控制, 创建过程更加清晰。
  3. 每个具体的建造者都可以创建出完整的产品对象, 而且是相互独立的。 因此, 调用端可以通过不同的具体建造者就可以得到不同的对象。当有新的产品出现时, 不需要改变原有代码, 只需要添加一个建造者即可。

举例

现在如果我们想建造一个胖小人,有五官的。那我们只需要添加一个PersonFatBuilder类就可以了, 不需要改原有代码。

public class PersonFatBuilder extends PersonBuilder {
public PersonFatBuilder(Graphics graphics) {
super(graphics);
}
@Override
public void buildHead() {
graphics.drawOval(50, 20, 30, 30);
graphics.drawArc(50, 30, 10, 5, 45, 135);
graphics.drawArc(70, 30, 10, 5, 45, 135);
graphics.drawArc(60, 35, 10, 5, 200, 135);
} @Override
public void buildBody() {
graphics.drawRect(55, 50, 20, 50);
} @Override
public void buildArmLeft() {
graphics.drawLine(55, 50, 40, 100);
} @Override
public void buildArmRight() {
graphics.drawLine(75, 50, 90, 100);
} @Override
public void buildLegLeft() {
graphics.drawLine(55, 100, 45, 150);
} @Override
public void buildLegRight() {
graphics.drawLine(75, 100, 85, 150);
}
}

结果:

Java设计模式-建造者(Builder)模式的更多相关文章

  1. Java设计模式之builder模式

    Java设计模式之builder模式 今天学mybatis的时候,知道了SQLSessionFactory使用的是builder模式来生成的.再次整理一下什么是builder模式以及应用场景. 1. ...

  2. 设计模式--建造者(Builder)模式

    将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示                                                         --<设计模 ...

  3. 3.java设计模式-建造者模式

    Java设计模式-建造者模式 在<JAVA与模式>一书中开头是这样描述建造(Builder)模式的: 建造模式是对象的创建模式.建造模式可以将一个产品的内部表象(internal repr ...

  4. 设计模式:Builder模式

    设计模式:Builder模式 一.前言    今天我们讨论一下Builder建造者模式,这个Builder,其实和模板模式非常的像,但是也有区别,那就是在模板模式中父类对子类中的实现进行操作,在父类之 ...

  5. 折腾Java设计模式之模板方法模式

    博客原文地址:折腾Java设计模式之模板方法模式 模板方法模式 Define the skeleton of an algorithm in an operation, deferring some ...

  6. java设计模式6--适配器模式(Adapter )

    本文地址:http://www.cnblogs.com/archimedes/p/java-adapter-pattern.html,转载请注明源地址. 适配器模式(别名:包装器) 将一个类的接口转换 ...

  7. java设计模式5--原型模式(Prototype)

    本文地址:http://www.cnblogs.com/archimedes/p/java-prototype-pattern.html,转载请注明源地址. 原型模式 用原型实例指定创建对象的种类,并 ...

  8. Java设计模式——装饰者模式

    JAVA 设计模式 装饰者模式 用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式 ...

  9. 浅析JAVA设计模式之工厂模式(一)

    1 工厂模式简单介绍 工厂模式的定义:简单地说,用来实例化对象,取代new操作. 工厂模式专门负责将大量有共同接口的类实例化.工作模式能够动态决定将哪一个类实例化.不用先知道每次要实例化哪一个类. 工 ...

随机推荐

  1. 远程桌面web连接

      我们可以利用web浏览器搭配远程桌面技术来连接远程计算机,这个功能被称为远程桌面web连接(Remote desktop web connection),要享有此功能,请先在网络上一台window ...

  2. Spark 集群管理命令

    [启动] # 启动所有服务 start-all.sh # 启动 master start-master.sh # 启动所有 worker start-slaves.sh # 启动单个 worker s ...

  3. 49_分析代理类的作用与原理及AOP概念

    生活中的代理 武汉人从武汉的代理商手中买联想电脑和直接跑到北京传智播客旁边来找联想总部买电脑,你觉得最终的主体业务目标有什么区别吗?基本上一样吧,都解决了核心问题,但是,一点区别都没有吗?从代理商那里 ...

  4. Mac如何搭建 配置 virtualenv python虚拟环境(超级详细,适合小白)

    首先去python官网 下载python3的 安装包安装: https://www.python.org/ftp/python/3.6.5/python-3.6.5-macosx10.9.pkg 安装 ...

  5. 团队作业7——第二次项目冲刺(Beta版本)day2

    项目成员:  曾海明(组长):201421122036 于波(组员):201421122058 蓝朝浩(组员):201421122048 王珏 (组员):201421122057 叶赐红(组员):20 ...

  6. RMAN 备份数据库到DISK后进行数据恢复

    RMAN 备份数据库到DISK,然后进行数据恢复 一.rman备份 1. 全备脚本 vi bakup_level0.sql connect target / run { allocate channe ...

  7. go变量和常量

    一.变量 1. 命名规则:字母或者_下划线开头 2.“:=” 这种模式只能用于函数内部,常量const不能用这种模式来定义 二.常量 1. 常量const必须在定义的时候就赋值 2. 常量的值在整个过 ...

  8. 【转】 [置顶] Android 通知栏Notification的整合 全面学习 (一个DEMO让你完全了解它)

    在Android的应用层中,涉及到很多应用框架,例如:Service框架,Activity管理机制,Broadcast机制,对话框框架,标题栏框架,状态栏框架,通知机制,ActionBar框架等等. ...

  9. 随手练——P1141 01迷宫

    1.暴力版 本质上就是求连通块数量,那么DFS或者BFS都行,暴力跑. 写完发现题目比较特殊,m次提问,那每次都暴力搜,肯定是要跑死了. #include <iostream> #incl ...

  10. 【测试123】ISTQB AL

    近一年时间加强了金融领域基础知识,希望能顺利获得FRM认证. 接下来因为工作需要,在测试工程师的角色上有所深入发展. 仔细想了下,一是管理上的角色转换,如何协调各个不同测试级别,以及如何成为一个称职满 ...