建造者模式:从面试场到软件工匠的必修课

78 阅读4分钟

面试官:“你能讲讲建造者模式吗?”

一位紧张的候选人正坐在面试室里,面试官用意味深长的语气问出了这个问题。房间里的气氛瞬间凝固了。
“建造者模式……”候选人开始组织语言,心中却暗暗叫苦:怎么让这个老生常谈的话题说得不落俗套?

“我来举个例子吧!”候选人忽然眼睛一亮,开始从一个场景讲起——


从餐厅点单到软件开发:建造者模式的真实写照

“你有没有遇到过这样的场景?”候选人侃侃而谈。

“你走进一家餐厅,告诉服务员你想要一个汉堡、一杯可乐,再加上薯条。接着,服务员微笑着点头,将你的需求传达给厨房,而你只需等待几分钟,美味的套餐就会送到你面前。你并不需要知道汉堡是如何制作的,甚至不需要在意薯条是炸的还是烤的。”

这时,面试官开始露出感兴趣的表情。

“其实,这就是建造者模式的核心思想——通过分步骤构建一个复杂对象,客户只需要提供需求,而具体如何实现由建造者负责。”


建造者模式:面试中的技术故事

候选人继续解释:“在软件开发中,我们常常需要创建复杂对象,比如一个房屋、汽车,或者一份报表。直接在客户端构造这些对象,会让代码变得杂乱且难以维护。而建造者模式通过分离对象的构建过程和表示,让这个问题迎刃而解。”


面试官:“能具体讲讲吗?”

“当然!”候选人微微一笑,拿起白板笔开始画图。


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);    }}

候选人:“建造者模式适用于哪些场景?”

  1. 创建复杂对象:
    当对象有多个可选参数或复杂构建逻辑时,例如汽车、报表生成器、游戏角色。
  2. 需要多种表示的对象:
    比如支持不同语言的文档生成器(HTML、PDF)。
  3. 构造步骤稳定,但对象类型经常变化:
    比如汽车制造流程始终不变,但车型有跑车、卡车等。

面试官点头:“还有什么缺点吗?”

候选人回答道:“当然有!虽然建造者模式有很多好处,但也有一些不足:”

  1. 代码复杂度增加:
    每个产品需要一个具体建造者类,可能增加代码量。
  2. 适用范围有限:
    主要适用于对象构造过程复杂的场景,对于简单对象不适合。

候选人的最后总结

“建造者模式的本质就是将复杂对象的构建逻辑分离出来,使代码清晰、灵活且易于扩展。就像一位优秀的厨师按照菜谱一步步制作美食,它可以帮我们在项目中更高效地构建复杂对象。”

面试官微微一笑:“很好,接下来我们聊聊工厂模式吧!”