Java设计模式-建造者(Builder)模式
@
最近在看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
类型的成员变量。
优点
Director
不需要知道Product
的内部细节, 它只提供需要的信息给建设者, 由具体的建造者ConcreateBuilder
处理从而完成产品的构造。- 建造者模式将复杂的产品创建过程分散到了不同的对象中, 从而实现对产品创建过程更精确的控制, 创建过程更加清晰。
- 每个具体的建造者都可以创建出完整的产品对象, 而且是相互独立的。 因此, 调用端可以通过不同的具体建造者就可以得到不同的对象。当有新的产品出现时, 不需要改变原有代码, 只需要添加一个建造者即可。
举例
现在如果我们想建造一个胖小人,有五官的。那我们只需要添加一个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);
}
}
结果:
作者:阿进的写字台
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义