建造者模式是设计模式中的一个常用模式,其核心在于将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
为什么选择建造者模式?
当一个对象需要多个步骤进行构建,或者构建对象的过程需要多个独立的组件和接口时,建造者模式是一个很好的选择。它提供了一种清晰的方式来保持对象的创建过程和最终表示的分离。
业务场景深入分析:
-
文档转换器:考虑一个工具,它可以从一个文档格式转换到另一个格式,例如从Markdown转换为HTML或PDF。不同的输出格式可能需要不同的构建步骤和组件。
-
用户界面库:在构建用户界面时,可能需要分步骤构建各个界面组件。例如,一个窗口可能包括标题栏、滚动条、按钮等,这些组件可能需要按特定的顺序和配置创建。
-
食品订单系统:考虑一个在线订餐系统,客户可以自定义他们的汉堡或披萨,选择不同的配料和酱料。这样的系统可以使用建造者模式来分步创建食品订单。
优势:
- 分离构建和表示:建造者模式提供了一种机制,使得对象的创建过程与其表示完全分离,提高了模块化和重用性。
- 更清晰的代码:通过使用建造者模式,代码变得更加清晰和易于管理。
缺点:
- 增加系统复杂性:由于增加了额外的建造者类和导演类,可能使系统变得更加复杂。
代码示例:
1. C#:
public class Product
{
public List<string> Parts { get; } = new List<string>();
}
public abstract class Builder
{
public abstract void BuildPartA();
public abstract void BuildPartB();
public abstract Product GetResult();
}
public class ConcreteBuilder : Builder
{
private Product _product = new Product();
public override void BuildPartA()
{
_product.Parts.Add("Part A");
}
public override void BuildPartB()
{
_product.Parts.Add("Part B");
}
public override Product GetResult()
{
return _product;
}
}
public class Director
{
public void Construct(Builder builder)
{
builder.BuildPartA();
builder.BuildPartB();
}
}
// 使用
Director director = new Director();
Builder builder = new ConcreteBuilder();
director.Construct(builder);
Product product = builder.GetResult();
2. C++:
#include <iostream>
#include <vector>
using namespace std;
class Product {
public:
vector<string> parts;
void Display() {
for (string part : parts) {
cout << part << endl;
}
}
};
class Builder {
public:
virtual void BuildPartA() = 0;
virtual void BuildPartB() = 0;
virtual Product* GetResult() = 0;
};
class ConcreteBuilder : public Builder {
private:
Product* product = new Product();
public:
void BuildPartA() override {
product->parts.push_back("Part A");
}
void BuildPartB() override {
product->parts.push_back("Part B");
}
Product* GetResult() override {
return product;
}
};
class Director {
public:
void Construct(Builder* builder) {
builder->BuildPartA();
builder->BuildPartB();
}
};
// Usage
int main() {
Director director;
Builder* builder = new ConcreteBuilder();
director.Construct(builder);
Product* product = builder->GetResult();
product->Display();
delete product;
delete builder;
return 0;
}
3. Java:
import java.util.ArrayList;
import java.util.List;
class Product {
private List<String> parts = new ArrayList<>();
public void add(String part) {
parts.add(part);
}
public void display() {
for (String part : parts) {
System.out.println(part);
}
}
}
abstract class Builder {
public abstract void buildPartA();
public abstract void buildPartB();
public abstract Product getResult();
}
class ConcreteBuilder extends Builder {
private Product product = new Product();
@Override
public void buildPartA() {
product.add("Part A");
}
@Override
public void buildPartB() {
product.add("Part B");
}
@Override
public Product getResult() {
return product;
}
}
class Director {
public void construct(Builder builder) {
builder.buildPartA();
builder.buildPartB();
}
}
// Usage
public class BuilderExample {
public static void main(String[] args) {
Director director = new Director();
Builder builder = new ConcreteBuilder();
director.construct(builder);
Product product = builder.getResult();
product.display();
}
}
4. Python:
class Product:
def __init__(self):
self.parts = []
def add(self, part):
self.parts.append(part)
def display(self):
for part in self.parts:
print(part)
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.add("Part A")
def build_part_b(self):
self.product.add("Part B")
def get_result(self):
return self.product
class Director:
@staticmethod
def construct(builder):
builder.build_part_a()
builder.build_part_b()
# Usage
if __name__ == "__main__":
director = Director()
builder = ConcreteBuilder()
director.construct(builder)
product = builder.get_result()
product.display()
5. Go:
package main
import (
"fmt"
)
// Product class
type Product struct {
parts []string
}
func (p *Product) Add(part string) {
p.parts = append(p.parts, part)
}
func (p *Product) Display() {
for _, part := range p.parts {
fmt.Println(part)
}
}
// Builder interface
type Builder interface {
BuildPartA()
BuildPartB()
GetResult() *Product
}
// ConcreteBuilder class
type ConcreteBuilder struct {
product *Product
}
func NewConcreteBuilder() *ConcreteBuilder {
return &ConcreteBuilder{product: &Product{}}
}
func (b *ConcreteBuilder) BuildPartA() {
b.product.Add("Part A")
}
func (b *ConcreteBuilder) BuildPartB() {
b.product.Add("Part B")
}
func (b *ConcreteBuilder) GetResult() *Product {
return b.product
}
// Director class
type Director struct {
builder Builder
}
func (d *Director) Construct(builder Builder) {
d.builder = builder
builder.BuildPartA()
builder.BuildPartB()
}
// Usage
func main() {
director := &Director{}
builder := NewConcreteBuilder()
director.Construct(builder)
product := builder.GetResult()
product.Display()
}
6. TypeScript:
class Product {
private parts: string[] = [];
public add(part: string): void {
this.parts.push(part);
}
public display(): void {
for (let part of this.parts) {
console.log(part);
}
}
}
abstract class Builder {
public abstract buildPartA(): void;
public abstract buildPartB(): void;
public abstract getResult(): Product;
}
class ConcreteBuilder extends Builder {
private product = new Product();
public buildPartA(): void {
this.product.add("Part A");
}
public buildPartB(): void {
this.product.add("Part B");
}
public getResult(): Product {
return this.product;
}
}
class Director {
private builder: Builder;
public construct(builder: Builder): void {
this.builder = builder;
builder.buildPartA();
builder.buildPartB();
}
}
// Usage
let director = new Director();
let builder = new ConcreteBuilder();
director.construct(builder);
let product = builder.getResult();
product.display();
总结:
建造者模式提供了一种分离对象的构建过程和表示的方法,使得我们可以独立地改变对象的创建过程和表示。这种分离带来的主要优势是增加了代码的模块化和重用性,使得代码更加清晰和易于管理。在设计复杂对象时,建造者模式是一个非常有价值的工具。