定义
建造者模式(Builder Pattern)是一种创建型设计模式,它将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。该模式允许通过多个简单的步骤逐步构建出一个复杂的对象,用户只需指定复杂对象的类型和内容,而无需了解内部具体的构建细节。
类图

角色
建造者模式包含四个主要角色,其类图结构如下:
-
产品角色(Product):包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件。例如,一个房屋对象,它可能包含墙体、屋顶、门窗等部件。
-
抽象建造者(Builder):定义了创建产品各个子部件的抽象方法接口,通常还包含一个返回复杂产品的方法 getResult()。例如,定义一个建造房屋的抽象接口,其中包含创建墙体、屋顶、门窗等抽象方法。
-
具体建造者(Concrete Builder):实现抽象建造者接口,完成复杂产品各个部件的具体创建方法。例如,实现建造普通房屋的具体建造者类,实现抽象接口中创建墙体、屋顶、门窗等具体逻辑。
-
指挥者(Director):调用建造者对象中的部件构造与装配方法完成复杂对象的创建,指挥者中不涉及具体产品的信息。例如,一个房屋建造指挥者,它调用建造者对象的方法,按照一定顺序构建房屋。
优缺点
优点
-
封装性好,构建和表示分离:将复杂对象的构建过程封装在建造者类中,客户端只需要关心如何使用建造者创建对象,而无需了解对象内部的构建细节,使得代码的耦合度降低,维护性提高。
-
拓展性好:各个具体的建造者相互独立,增加新的具体建造者无需修改原有类库的代码,符合 "开闭原则"。例如,如果需要增加一种新类型的房屋建造,只需要新增一个具体建造者类实现抽象建造者接口即可,不会影响到其他部分的代码。
-
便于控制细节风险:客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其他模块产生任何影响。例如,在建造房屋时,建造者可以根据实际情况对墙体的厚度、屋顶的材质等细节进行调整,而不会影响到房屋的整体结构和其他部分的构建。
缺点
-
产品的组成部分必须相同,限制适用范围:该模式要求产品的组成部分相对固定,如果产品的结构和组成经常变化,使用建造者模式可能不太合适。例如,如果房屋的基本组成部分(如墙体、屋顶、门窗)经常变动,那么使用建造者模式就需要频繁修改各个建造者类和相关的代码,维护成本较高。
-
后期维护成本较大:如果产品的内部变化复杂,产品内部发生变化时,建造者也要同步修改。例如,当房屋的结构发生重大变化,如从传统的砖混结构变为框架结构时,所有的具体建造者类都需要相应地修改创建部件的方法,这可能会涉及到大量的代码修改和测试工作。
建造者模式和工厂模式比较
建造者模式和工厂模式都属于创建型设计模式,但它们的关注点不同:
-
建造者模式注重零部件的组装过程:强调通过一步步的构建过程来创建复杂对象,将对象的构建和表示分离,更侧重于描述如何将多个简单部件组合成一个复杂对象。例如,建造房屋时,关注墙体、屋顶、门窗等部件如何按照一定顺序组装成一个完整的房屋。
-
工厂模式更注重零部件的创建过程:主要用于创建对象,它提供了一种创建对象的方式,将对象的创建和使用分离,重点在于根据不同的条件创建不同类型的对象。例如,工厂模式可以根据客户需求创建不同类型的汽车,而不关注汽车内部零部件的组装过程。
在实际应用中,两者可以结合使用。例如,在生产汽车时,工厂模式负责创建汽车的各个零部件(如发动机、轮胎等),而建造者模式负责将这些零部件组装成一辆完整的汽车。
使用场景
创建复杂对象结构
当需要创建的对象是由多个部件构成,且这些部件的组合方式多样时,建造者模式能派上大用场。以电商平台为例,订单对象的创建过程颇为复杂,订单包含用户信息、收货地址、商品列表、促销优惠、支付方式等多个部件。利用建造者模式,可将订单的构建过程进行拆分,让具体建造者分别负责构建各个部件,指挥者按照既定的业务逻辑,将这些部件组合成完整的订单对象。这样一来,不仅创建订单的逻辑更加清晰,后续若要新增或修改订单的某个部件,只需调整相应的建造者类,不会对整体的订单创建流程造成过大影响。
用户交互与配置生成
在交互式应用程序中,用户通常会通过界面设置各种参数来生成特定的对象。以游戏开发为例,玩家在创建游戏角色时,需要对角色的种族、职业、外貌、技能等多项属性进行配置。运用建造者模式,可为每种角色类型创建对应的具体建造者,玩家通过界面输入配置信息,指挥者依据这些信息调用相应的建造者方法,构建出符合玩家需求的游戏角色。这种方式将角色创建的复杂逻辑封装在建造者和指挥者中,使得用户界面与角色创建逻辑解耦,提升了代码的可维护性和扩展性。
分步骤创建和延迟创建
在某些场景下,对象的创建并非一蹴而就,可能需要分多个步骤完成,或者根据特定条件延迟创建对象的某些部分。以报表生成系统为例,报表对象可能包含数据表格、图表、文字说明等多个部分。借助建造者模式,可以先创建报表的基本结构,然后根据用户的请求逐步生成数据表格、图表等内容。当数据量较大时,还能通过延迟创建的方式,避免在系统启动时就进行大量的数据加载和报表生成操作,提升系统的响应速度和性能。
多平台适配
当需要为不同的平台或环境创建对象时,建造者模式同样适用。以移动应用开发为例,应用可能需要针对 iOS 和 Android 平台生成不同风格的界面布局。通过创建不同平台对应的具体建造者,分别负责生成适用于各自平台的界面元素,指挥者则根据运行平台调用相应的建造者,创建出符合平台特性的界面。这种方式将平台相关的代码封装在具体建造者中,便于对不同平台的界面进行独立维护和更新。
构建链式操作对象
在一些流式 API 的设计中,常常会使用建造者模式来实现链式操作。以 Java 的Stream API 为例,通过链式调用各种方法,可以对数据进行筛选、映射、排序等一系列操作。建造者模式通过链式调用的方式,将多个操作步骤串联起来,使代码更加简洁和可读。用户只需关注每个操作的逻辑,而无需关心对象的创建和组装过程,极大地提升了代码的开发效率。
使用案例
Java StringBuilder
在 Java 中,StringBuilder 类的使用类似于建造者模式。StringBuilder 用于创建可变的字符串对象,它提供了一系列方法来逐步构建字符串。
1. 类比建造者模式的角色:
- StringBuilder 类可以看作是具体建造者,它实现了构建字符串的具体方法。例如,append() 方法用于将各种类型的数据追加到字符串中,类似于具体建造者创建产品部件的方法。
- StringBuilder 类中的 toString() 方法可以类比为抽象建造者中的 getResult() 方法,用于返回最终构建好的字符串对象(产品)。
2. 使用示例:
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(", ");
sb.append("World!");
String result = sb.toString();
System.out.println(result);
通过 StringBuilder 的 append() 方法逐步构建字符串,最后通过 toString() 方法得到完整的字符串,体现了建造者模式逐步构建复杂对象的思想。虽然 StringBuilder 并不是严格意义上的建造者模式实现,但它的设计思路和使用方式与建造者模式有相似之处,帮助我们更好地理解和运用建造者模式的概念。