生成器模式
创建型模式
访问次数: 11
生成器模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
视频教程
类图
classDiagram
class Director {
-builder: Builder
+construct()
}
class Builder {
<<interface>>
+buildPartA()
+buildPartB()
+buildPartC()
+getResult() Product
}
class ConcreteBuilder {
-product: Product
+buildPartA()
+buildPartB()
+buildPartC()
+getResult() Product
}
class Product {
-partA: String
-partB: String
-partC: String
+setPartA(partA: String)
+setPartB(partB: String)
+setPartC(partC: String)
}
Director --> Builder
Builder <|-- ConcreteBuilder
ConcreteBuilder --> Product
源代码示例
// 产品类
class Product {
private String partA;
private String partB;
private String partC;
public void setPartA(String partA) {
this.partA = partA;
}
public void setPartB(String partB) {
this.partB = partB;
}
public void setPartC(String partC) {
this.partC = partC;
}
@Override
public String toString() {
return "Product{partA='" + partA + "', partB='" + partB + "', partC='" + partC + "'}";
}
}
// 抽象建造者
interface Builder {
void buildPartA();
void buildPartB();
void buildPartC();
Product getResult();
}
// 具体建造者
class ConcreteBuilder implements Builder {
private Product product = new Product();
@Override
public void buildPartA() {
product.setPartA("Part A");
}
@Override
public void buildPartB() {
product.setPartB("Part B");
}
@Override
public void buildPartC() {
product.setPartC("Part C");
}
@Override
public Product getResult() {
return product;
}
}
// 指挥者
class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public Product construct() {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
return builder.getResult();
}
}
# 产品类
class Product:
def __init__(self):
self.part_a = None
self.part_b = None
self.part_c = None
def set_part_a(self, part_a):
self.part_a = part_a
def set_part_b(self, part_b):
self.part_b = part_b
def set_part_c(self, part_c):
self.part_c = part_c
def __str__(self):
return f"Product{{partA='{self.part_a}', partB='{self.part_b}', partC='{self.part_c}'}}"
# 抽象建造者
from abc import ABC, abstractmethod
class Builder(ABC):
@abstractmethod
def build_part_a(self):
pass
@abstractmethod
def build_part_b(self):
pass
@abstractmethod
def build_part_c(self):
pass
@abstractmethod
def get_result(self):
pass
# 具体建造者
class ConcreteBuilder(Builder):
def __init__(self):
self.product = Product()
def build_part_a(self):
self.product.set_part_a("Part A")
def build_part_b(self):
self.product.set_part_b("Part B")
def build_part_c(self):
self.product.set_part_c("Part C")
def get_result(self):
return self.product
# 指挥者
class Director:
def __init__(self, builder):
self.builder = builder
def construct(self):
self.builder.build_part_a()
self.builder.build_part_b()
self.builder.build_part_c()
return self.builder.get_result()
# 使用示例
if __name__ == "__main__":
builder = ConcreteBuilder()
director = Director(builder)
product = director.construct()
print(product)
应用场景
当需要创建复杂对象,且对象的构建过程需要分步骤进行时。应用场景包括:
1)构建一个复杂的SQL查询,需要逐步添加SELECT、FROM、WHERE、ORDER BY等子句
2)创建复杂的邮件对象,需要设置发件人、收件人、主题、正文、附件等部分
3)构建HTTP请求对象,需要设置URL、请求头、请求体、认证信息、超时设置等参数
4)创建复杂的配置文件对象,需要设置数据库连接、缓存配置、日志配置、安全配置等多个部分
5)构建游戏角色对象,需要设置基础属性、技能、装备、背包、任务等多个复杂组件
精选场景详解 —— SQL 构建:分步组装复杂查询
问题背景
动态报表需要按条件拼接 SELECT、JOIN、WHERE、ORDER BY。用字符串拼接易出错、难复用,且无法保证「必填子句」与构造顺序。
模式如何解决
选用生成器(Builder)模式:SqlQueryBuilder 提供 select、from、where、orderBy、build 等步骤方法;Director(或业务服务)按场景编排调用顺序,最终 build() 得到不可变的 SqlQuery。
好处:
1)把复杂构造过程拆成清晰步骤;
2)同一套步骤可构建不同查询变体;
3)可在 build 时校验完整性(例如必须有 FROM)。
与工厂的区别:工厂关注「创建哪个类」,Builder 关注「同一个复杂对象如何一步步填满」。
场景模型(角色映射)
将模式中的抽象角色映射到该业务领域的具体类:
classDiagram
class SqlQueryBuilder {
<<interface>>
+select(cols: String) SqlQueryBuilder
+from(table: String) SqlQueryBuilder
+where(cond: String) SqlQueryBuilder
+orderBy(expr: String) SqlQueryBuilder
+build() SqlQuery
}
class DefaultSqlQueryBuilder {
-query: SqlQuery
+select(cols: String) SqlQueryBuilder
+from(table: String) SqlQueryBuilder
+where(cond: String) SqlQueryBuilder
+orderBy(expr: String) SqlQueryBuilder
+build() SqlQuery
}
class SqlQuery {
-selectClause: String
-fromClause: String
-whereClause: String
-orderByClause: String
+toSql() String
}
class ReportQueryDirector {
-builder: SqlQueryBuilder
+buildSalesReport() SqlQuery
+buildUserReport() SqlQuery
}
SqlQueryBuilder <|.. DefaultSqlQueryBuilder
DefaultSqlQueryBuilder --> SqlQuery
ReportQueryDirector --> SqlQueryBuilder