建造者模式解读:分步构造复杂对象!

109 阅读4分钟

建造者模式是设计模式中的一个常用模式,其核心在于将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

为什么选择建造者模式?
当一个对象需要多个步骤进行构建,或者构建对象的过程需要多个独立的组件和接口时,建造者模式是一个很好的选择。它提供了一种清晰的方式来保持对象的创建过程和最终表示的分离。

业务场景深入分析

  1. 文档转换器:考虑一个工具,它可以从一个文档格式转换到另一个格式,例如从Markdown转换为HTML或PDF。不同的输出格式可能需要不同的构建步骤和组件。

  2. 用户界面库:在构建用户界面时,可能需要分步骤构建各个界面组件。例如,一个窗口可能包括标题栏、滚动条、按钮等,这些组件可能需要按特定的顺序和配置创建。

  3. 食品订单系统:考虑一个在线订餐系统,客户可以自定义他们的汉堡或披萨,选择不同的配料和酱料。这样的系统可以使用建造者模式来分步创建食品订单。

优势

  • 分离构建和表示:建造者模式提供了一种机制,使得对象的创建过程与其表示完全分离,提高了模块化和重用性。
  • 更清晰的代码:通过使用建造者模式,代码变得更加清晰和易于管理。

缺点

  • 增加系统复杂性:由于增加了额外的建造者类和导演类,可能使系统变得更加复杂。

代码示例

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

总结
建造者模式提供了一种分离对象的构建过程和表示的方法,使得我们可以独立地改变对象的创建过程和表示。这种分离带来的主要优势是增加了代码的模块化和重用性,使得代码更加清晰和易于管理。在设计复杂对象时,建造者模式是一个非常有价值的工具。