面试官:“你能讲讲建造者模式吗?”
一位紧张的候选人正坐在面试室里,面试官用意味深长的语气问出了这个问题。房间里的气氛瞬间凝固了。
“建造者模式……”候选人开始组织语言,心中却暗暗叫苦:怎么让这个老生常谈的话题说得不落俗套?
“我来举个例子吧!”候选人忽然眼睛一亮,开始从一个场景讲起——
从餐厅点单到软件开发:建造者模式的真实写照
“你有没有遇到过这样的场景?”候选人侃侃而谈。
“你走进一家餐厅,告诉服务员你想要一个汉堡、一杯可乐,再加上薯条。接着,服务员微笑着点头,将你的需求传达给厨房,而你只需等待几分钟,美味的套餐就会送到你面前。你并不需要知道汉堡是如何制作的,甚至不需要在意薯条是炸的还是烤的。”
这时,面试官开始露出感兴趣的表情。
“其实,这就是建造者模式的核心思想——通过分步骤构建一个复杂对象,客户只需要提供需求,而具体如何实现由建造者负责。”
建造者模式:面试中的技术故事
候选人继续解释:“在软件开发中,我们常常需要创建复杂对象,比如一个房屋、汽车,或者一份报表。直接在客户端构造这些对象,会让代码变得杂乱且难以维护。而建造者模式通过分离对象的构建过程和表示,让这个问题迎刃而解。”
面试官:“能具体讲讲吗?”
“当然!”候选人微微一笑,拿起白板笔开始画图。
1. 一个真实的场景:建造一辆汽车
“假设我们要为一家汽车制造厂开发系统,支持生产不同类型的汽车,比如跑车、SUV、卡车。”
“每种汽车都有相同的构建步骤,比如安装引擎、组装轮胎、组装车身。但每种汽车的具体实现细节却不同,比如跑车用的是 V8 引擎,SUV 用的是大轮胎,而卡车则需要更坚固的车身。”
“如果在客户端直接写这些代码,会显得混乱且难以扩展。但通过建造者模式,我们可以让代码变得清晰。”
2. 建造者模式的角色
“建造者模式分为四个主要角色:”
- 建造者接口(Builder): 定义创建产品的步骤,比如
buildEngine()、buildWheels()等。 - 具体建造者(Concrete Builder): 实现不同类型的建造逻辑,比如跑车的建造者和卡车的建造者。
- 指挥者(Director): 负责调用建造者的方法,按照既定流程构造产品。
- 产品(Product): 最终的复杂对象,比如汽车。
候选人:“让我展示一下代码。”
产品类
public class Car { private String engine; private String wheels; private String body; public void setEngine(String engine) { this.engine = engine; } public void setWheels(String wheels) { this.wheels = wheels; } public void setBody(String body) { this.body = body; } @Override public String toString() { return "Car [Engine=" + engine + ", Wheels=" + wheels + ", Body=" + body + "]"; }}
建造者接口
public interface CarBuilder { void buildEngine(); void buildWheels(); void buildBody(); Car getCar();}
具体建造者:跑车建造者
public class SportsCarBuilder implements CarBuilder { private Car car = new Car(); @Override public void buildEngine() { car.setEngine("V8 Engine"); } @Override public void buildWheels() { car.setWheels("Sports Wheels"); } @Override public void buildBody() { car.setBody("Aerodynamic Body"); } @Override public Car getCar() { return car; }}
指挥者类
public class Director { private CarBuilder builder; public Director(CarBuilder builder) { this.builder = builder; } public Car constructCar() { builder.buildEngine(); builder.buildWheels(); builder.buildBody(); return builder.getCar(); }}
客户端调用
public class BuilderPatternExample { public static void main(String[] args) { CarBuilder builder = new SportsCarBuilder(); Director director = new Director(builder); Car car = director.constructCar(); System.out.println(car); }}
候选人:“建造者模式适用于哪些场景?”
- 创建复杂对象:
当对象有多个可选参数或复杂构建逻辑时,例如汽车、报表生成器、游戏角色。 - 需要多种表示的对象:
比如支持不同语言的文档生成器(HTML、PDF)。 - 构造步骤稳定,但对象类型经常变化:
比如汽车制造流程始终不变,但车型有跑车、卡车等。
面试官点头:“还有什么缺点吗?”
候选人回答道:“当然有!虽然建造者模式有很多好处,但也有一些不足:”
- 代码复杂度增加:
每个产品需要一个具体建造者类,可能增加代码量。 - 适用范围有限:
主要适用于对象构造过程复杂的场景,对于简单对象不适合。
候选人的最后总结
“建造者模式的本质就是将复杂对象的构建逻辑分离出来,使代码清晰、灵活且易于扩展。就像一位优秀的厨师按照菜谱一步步制作美食,它可以帮我们在项目中更高效地构建复杂对象。”
面试官微微一笑:“很好,接下来我们聊聊工厂模式吧!”