建造者模式(Builder Pattern) 是一种创建型设计模式,它允许你逐步构造复杂对象,而不必使用一个庞大的构造函数。建造者模式的主要目的是将对象的构建过程与其表示分离,从而使得相同的构建过程可以创建不同的表示。
主要角色
- Builder(抽象建造者):定义创建一个产品对象的各个部件的接口。
- ConcreteBuilder(具体建造者):实现 Builder 接口,构建和装配各个部件,最终构造出产品对象。
- Director(导演类):负责调用具体的建造者来构建产品的各个部件。
- Product(产品类):表示被构造的复杂对象,包含多个部件。
2. UML 类图及解释
UML 类图
+----------------+ +---------------------+
| Director | | ConcreteBuilder |
|----------------| |---------------------|
| - builder: Builder | - product: Product |
| | |
| + construct(): void | + buildPartA(): void|
| + setBuilder(builder: Builder):| + buildPartB(): void|
| void | + getResult(): Product |
+----------------+ +---------------------+
| ^
| |
| |
v |
+----------------+ |
| Builder | |
|----------------| |
| - product: Product |
| +---------+
| + buildPartA(): void |
| + buildPartB(): void |
| + getResult(): Product |
+----------------+ |
+----------------+ |
| Product | |
|----------------| |
| - partA: string |
| - partB: string |
| +---------+
| + setPartA(partA: string): void |
| + setPartB(partB: string): void |
+----------------+ |
类图解释
- Director:负责调用具体的建造者来构建产品的各个部件。它不依赖于具体的产品类,而是依赖于抽象建造者。
- Builder:定义了一个创建产品对象的接口,但不具体实现。具体实现由具体的建造者类完成。
- ConcreteBuilder:实现了 Builder 接口,负责构建和装配各个部件,最终构造出产品对象。
- Product:表示被构造的复杂对象,包含多个部件。具体的建造者类会逐步构建这个对象。
3. 代码案例及逻辑详解
Java 代码案例
// 产品类
class Product {
private String partA;
private String partB;
public void setPartA(String partA) {
this.partA = partA;
}
public void setPartB(String partB) {
this.partB = partB;
}
@Override
public String toString() {
return "Product [partA=" + partA + ", partB=" + partB + "]";
}
}
// 抽象建造者
interface Builder {
void buildPartA();
void buildPartB();
Product getResult();
}
// 具体建造者
class ConcreteBuilder implements Builder {
private Product product;
public ConcreteBuilder() {
this.product = new Product();
}
@Override
public void buildPartA() {
product.setPartA("Part A");
}
@Override
public void buildPartB() {
product.setPartB("Part B");
}
@Override
public Product getResult() {
return product;
}
}
// 导演类
class Director {
private Builder builder;
public void setBuilder(Builder builder) {
this.builder = builder;
}
public void construct() {
builder.buildPartA();
builder.buildPartB();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Director director = new Director();
ConcreteBuilder builder = new ConcreteBuilder();
director.setBuilder(builder);
director.construct();
Product product = builder.getResult();
System.out.println(product);
}
}
C++ 代码案例
#include <iostream>
#include <string>
// 产品类
class Product {
public:
std::string partA;
std::string partB;
void setPartA(const std::string& partA) {
this->partA = partA;
}
void setPartB(const std::string& partB) {
this->partB = partB;
}
friend std::ostream& operator<<(std::ostream& os, const Product& p) {
return os << "Product [partA=" << p.partA << ", partB=" << p.partB << "]";
}
};
// 抽象建造者
class Builder {
public:
virtual void buildPartA() = 0;
virtual void buildPartB() = 0;
virtual Product* getResult() = 0;
};
// 具体建造者
class ConcreteBuilder : public Builder {
private:
Product* product;
public:
ConcreteBuilder() {
product = new Product();
}
~ConcreteBuilder() {
delete product;
}
void buildPartA() override {
product->setPartA("Part A");
}
void buildPartB() override {
product->setPartB("Part B");
}
Product* getResult() override {
return product;
}
};
// 导演类
class Director {
private:
Builder* builder;
public:
void setBuilder(Builder* builder) {
this->builder = builder;
}
void construct() {
builder->buildPartA();
builder->buildPartB();
}
};
// 客户端代码
int main() {
Director director;
ConcreteBuilder builder;
director.setBuilder(&builder);
director.construct();
Product* product = builder.getResult();
std::cout << *product << std::endl;
return 0;
}
Python 代码案例
# 产品类
class Product:
def __init__(self):
self.partA = None
self.partB = None
def set_part_a(self, partA):
self.partA = partA
def set_part_b(self, partB):
self.partB = partB
def __str__(self):
return f"Product [partA={self.partA}, partB={self.partB}]"
# 抽象建造者
class Builder:
def build_part_a(self):
pass
def build_part_b(self):
pass
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 get_result(self):
return self.product
# 导演类
class Director:
def __init__(self):
self.builder = None
def set_builder(self, builder):
self.builder = builder
def construct(self):
self.builder.build_part_a()
self.builder.build_part_b()
# 客户端代码
if __name__ == "__main__":
director = Director()
builder = ConcreteBuilder()
director.set_builder(builder)
director.construct()
product = builder.get_result()
print(product)
Go 代码案例
package main
import "fmt"
// 产品类
type Product struct {
PartA string
PartB string
}
func (p *Product) SetPartA(partA string) {
p.PartA = partA
}
func (p *Product) SetPartB(partB string) {
p.PartB = partB
}
func (p *Product) String() string {
return fmt.Sprintf("Product [partA=%s, partB=%s]", p.PartA, p.PartB)
}
// 抽象建造者
type Builder interface {
BuildPartA()
BuildPartB()
GetResult() *Product
}
// 具体建造者
type ConcreteBuilder struct {
product *Product
}
func NewConcreteBuilder() *ConcreteBuilder {
return &ConcreteBuilder{product: &Product{}}
}
func (b *ConcreteBuilder) BuildPartA() {
b.product.SetPartA("Part A")
}
func (b *ConcreteBuilder) BuildPartB() {
b.product.SetPartB("Part B")
}
func (b *ConcreteBuilder) GetResult() *Product {
return b.product
}
// 导演类
type Director struct {
builder Builder
}
func (d *Director) SetBuilder(builder Builder) {
d.builder = builder
}
func (d *Director) Construct() {
d.builder.BuildPartA()
d.builder.BuildPartB()
}
// 客户端代码
func main() {
director := &Director{}
builder := NewConcreteBuilder()
director.SetBuilder(builder)
director.Construct()
product := builder.GetResult()
fmt.Println(product)
}
4. 总结
建造者模式 是一种非常有用的创建型设计模式,尤其适用于构建复杂的对象。通过将对象的构建过程与其表示分离,建造者模式使得相同的构建过程可以创建不同的表示。这种模式的主要优点包括:
- 封装性:将复杂的构建过程封装在建造者类中,客户端无需知道具体的构建细节。
- 灵活性:可以通过不同的建造者类创建不同类型的产品对象,增加了系统的灵活性。
- 可扩展性:增加新的建造者类时,无需修改现有代码,符合开闭原则。
然而,建造者模式也有一些缺点,例如代码量会增加,且在简单对象的构建中可能显得过于复杂。因此,选择是否使用建造者模式应根据具体的需求和场景来决定。