C#设计模式–建造者模式

换个更生活化的接口例子:🍕 披萨订单接口

public interface IPizza 
{
    string Name { get; set; }       // 披萨名称(如"超级至尊")
    string Size { get; set; }       // 尺寸(大/中/小)
    string Crust { get; set; }      // 饼底(薄脆/芝心/经典) 
    string[] Toppings { get; set; } // 配料(芝士/培根/蘑菇等)
    string Sauce { get; set; }      // 酱料(番茄/奶油/辣味)
    bool IsHot { get; set; }        // 是否加辣 
}

🍽️ 使用示例

// 具体披萨实现 
public class SupremePizza : IPizza 
{
    public string Name { get; set; } = "超级至尊";
    public string Size { get; set; } = "大";
    public string Crust { get; set; } = "芝心";
    public string[] Toppings { get; set; } = new[] { "培根", "香肠", "青椒", "洋葱" };
    public string Sauce { get; set; } = "番茄酱";
    public bool IsHot { get; set; } = true;
}
 
// 另一个实现 
public class SeafoodPizza : IPizza { /* 实现类似 */ }

🌟 为什么比手机例子更好?

更贴近生活:大家都点过披萨,容易理解各个属性
属性更直观

Size 替代 Memory(披萨尺寸 vs 手机内存)
Toppings 替代 Camera(配料 vs 摄像头)

可扩展性强

可以轻松添加新属性(如 ExtraCheese
配料用数组更符合实际情况

🏭 工厂模式应用

public interface IPizzaFactory 
{
    IPizza CreatePizza(string type);
}
 
public class PizzaHutFactory : IPizzaFactory 
{
    public IPizza CreatePizza(string type)
    {
        return type switch 
        {
            "Supreme" => new SupremePizza(),
            "Seafood" => new SeafoodPizza(),
            _ => throw new ArgumentException("不支持的披萨类型")
        };
    }
}

🆚 对比原手机接口

手机接口属性 披萨接口对应属性 说明
CPU Crust 核心部分(处理器 vs 饼底)
Screen Size 最直观的特征
Camera Toppings 特色功能(摄像头 vs 配料)
Battery IsHot 性能表现(续航 vs 辣度)

这个例子比手机配置参数更生动有趣,也更容易演示工厂模式生产不同产品的过程! 🍕

🍕 披萨建造者接口(修改版)

基于建造者模式,我们可以把披萨的制作过程拆分成多个构建步骤:

public interface IPizzaBuilder 
{
    IPizza Pizza { get; set; }  // 当前制作的披萨 
    
    void SelectSize();          // 选择尺寸 
    void ChooseCrust();         // 选择饼底 
    void AddSauce();            // 添加酱料 
    void AddToppings();         // 添加配料 
    void SetSpiceLevel();       // 设置辣度 
    
    IPizza GetPizza();          // 获取制作完成的披萨 
} 

🏗️ 具体建造者实现(以超级至尊披萨为例)

public class SupremePizzaBuilder : IPizzaBuilder 
{
    public IPizza Pizza { get; set; } = new Pizza();
    
    public void SelectSize()
    {
        Pizza.Size = "Large";
    }
 
    public void ChooseCrust()
    {
        Pizza.Crust = "Stuffed Crust";
    }
 
    public void AddSauce()
    {
        Pizza.Sauce = "Tomato Sauce";
    }
 
    public void AddToppings()
    {
        Pizza.Toppings = new[] { "Pepperoni", "Sausage", "Green Peppers", "Onions", "Mushrooms" };
    }
 
    public void SetSpiceLevel()
    {
        Pizza.IsHot = true;
        Pizza.SpiceLevel = "Medium";
    }
 
    public IPizza GetPizza()
    {
        Pizza.Name = "Supreme Pizza";
        return Pizza;
    }
}

👨‍🍳 主管类(指导建造过程)

public class PizzaChef 
{
    public IPizza MakePizza(IPizzaBuilder builder)
    {
        builder.SelectSize();
        builder.ChooseCrust();
        builder.AddSauce();
        builder.AddToppings();
        builder.SetSpiceLevel();
        return builder.GetPizza();
    }
}

🛒 使用示例

// 创建建造者 
var pizzaBuilder = new SupremePizzaBuilder();
 
// 主厨指导制作 
var chef = new PizzaChef();
var myPizza = chef.MakePizza(pizzaBuilder);
 
// 享用披萨 
Console.WriteLine($"我的披萨: {myPizza.Name}");
Console.WriteLine($"配料: {string.Join(", ", myPizza.Toppings)}");

🆚 与原建造者接口对比

手机建造步骤 披萨建造步骤 说明
BuildCPU() ChooseCrust() 核心部件(CPU vs 饼底)
BuildScreen() SelectSize() 外观特征(屏幕 vs 尺寸)
BuildCamera() AddToppings() 特色功能(摄像头 vs 配料)
BuildBattery() SetSpiceLevel() 性能参数(电池 vs 辣度)

这个建造者模式非常适合披萨制作场景,因为:

披萨制作本来就是分步骤的过程
可以灵活调整每个步骤(如辣度、配料)
可以创建不同风格的建造者(如意大利风格、美式风格)
确保最终产品(披萨)的完整性

🍕 具体建造者实现:海鲜披萨建造者

public class SeafoodPizzaBuilder : IPizzaBuilder 
{
    public IPizza Pizza { get; set; } = new Pizza();
    
    // 选择大号披萨
    public void SelectSize()
    {
        Pizza.Size = "Large";
        Console.WriteLine("选择了大号披萨");
    }
 
    // 选择薄脆饼底
    public void ChooseCrust()
    {
        Pizza.Crust = "Thin & Crispy";
        Console.WriteLine("选择了薄脆饼底");
    }
 
    // 添加白酱(海鲜披萨常用)
    public void AddSauce()
    {
        Pizza.Sauce = "Garlic White Sauce";
        Console.WriteLine("添加了蒜香白酱");
    }
 
    // 添加丰富的海鲜配料 
    public void AddToppings()
    {
        Pizza.Toppings = new[] { "Shrimp", "Squid", "Mussels", "Clams", "Garlic", "Parsley" };
        Console.WriteLine("添加了海鲜配料:虾、鱿鱼、青口、蛤蜊");
    }
 
    // 设置微辣 
    public void SetSpiceLevel()
    {
        Pizza.IsHot = true;
        Pizza.SpiceLevel = "Mild";
        Console.WriteLine("设置为微辣口味");
    }
 
    // 最终完成的海鲜披萨
    public IPizza GetPizza()
    {
        Pizza.Name = "Deluxe Seafood Pizza";
        Console.WriteLine("海鲜披萨制作完成!");
        return Pizza;
    }
}

🦞 使用示例

class Program 
{
    static void Main(string[] args)
    {
        // 1. 创建一个海鲜披萨建造者 
        var seafoodBuilder = new SeafoodPizzaBuilder();
        
        // 2. 主厨指导制作过程
        var chef = new PizzaChef();
        Console.WriteLine("开始制作海鲜披萨...");
        var seafoodPizza = chef.MakePizza(seafoodBuilder);
        
        // 3. 享用披萨 
        Console.WriteLine("
您点的披萨详情:");
        Console.WriteLine($"名称: {seafoodPizza.Name}");
        Console.WriteLine($"尺寸: {seafoodPizza.Size}");
        Console.WriteLine($"饼底: {seafoodPizza.Crust}");
        Console.WriteLine($"酱料: {seafoodPizza.Sauce}");
        Console.WriteLine($"配料: {string.Join(", ", seafoodPizza.Toppings)}");
        Console.WriteLine($"辣度: {(seafoodPizza.IsHot ? seafoodPizza.SpiceLevel : "不辣")}");
    }
}

🖨️ 输出结果示例

开始制作海鲜披萨...
选择了大号披萨 
选择了薄脆饼底 
添加了蒜香白酱
添加了海鲜配料:虾、鱿鱼、青口、蛤蜊
设置为微辣口味 
海鲜披萨制作完成!
 
您点的披萨详情:
名称: Deluxe Seafood Pizza 
尺寸: Large 
饼底: Thin & Crispy 
酱料: Garlic White Sauce
配料: Shrimp, Squid, Mussels, Clams, Garlic, Parsley 
辣度: Mild

🎯 设计要点

分步构建:每个方法只负责一个具体的构建步骤
灵活可变:可以轻松修改某个步骤(如改成”厚饼底”)
统一接口:所有建造者都遵循IPizzaBuilder接口
产品控制:最终通过GetPizza()返回完整产品

这个例子展示了如何为一个具体的海鲜披萨实现建造者模式,每个方法都对应披萨制作的一个实际步骤,最终组合成完整的产品。

🛠️ C#建造者模式通俗讲解(就像组装乐高)

建造者模式就像分步骤组装乐高玩具,把复杂对象的构建过程拆解成多个简单步骤,让组装过程更灵活可控。

🧩 实现过程四步走

1. 准备零件(产品类)

public class Pizza 
{
    public string Size { get; set; }
    public string Crust { get; set; }
    public List<string> Toppings { get; set; } = new();
    // 其他披萨属性...
}

2. 组装说明书(建造者接口)

public interface IPizzaBuilder 
{
    void BuildSize();      // 选择尺寸 
    void BuildCrust();     // 选择饼底 
    void BuildToppings();  // 添加配料 
    Pizza GetPizza();      // 获取成品 
}

3. 具体组装方案(具体建造者)

public class SpicyPizzaBuilder : IPizzaBuilder 
{
    private Pizza _pizza = new();
    
    public void BuildSize() => _pizza.Size = "Large";
    
    public void BuildCrust() => _pizza.Crust = "Thin";
    
    public void BuildToppings()
    {
        _pizza.Toppings.AddRange(new[] { "Pepperoni", "Jalapenos", "Hot Sauce" });
    }
    
    public Pizza GetPizza() => _pizza; 
}

4. 组装总监(指挥者)

public class PizzaChef 
{
    public Pizza MakePizza(IPizzaBuilder builder)
    {
        builder.BuildSize();      // 第一步:选尺寸 
        builder.BuildCrust();     // 第二步:选饼底 
        builder.BuildToppings();  // 第三步:加配料 
        return builder.GetPizza();// 第四步:取成品 
    }
}

🍽️ 使用示例(像点餐)

// 点一个辣味披萨 
var chef = new PizzaChef();
var spicyPizza = chef.MakePizza(new SpicyPizzaBuilder());
 
// 也可以换其他建造者 
var veggiePizza = chef.MakePizza(new VeggiePizzaBuilder());

🌟 模式优势

组装自由:可以通过改变建造者来创建不同产品
步骤可控:指挥者保证建造过程不会遗漏步骤
隐藏细节:用户不需要知道披萨怎么组装的

就像乐高玩具,同样的积木块(建造者接口),按照不同说明书(具体建造者),能组装出完全不同的作品(产品)!

🏗️ 通过抽象类实现建造者模式(完整案例)

建造者模式用抽象类实现,就像定义一个「万能组装说明书」,下面我们以组装电脑为例:

💻 1. 先定义产品(要组装的电脑)

public class Computer 
{
    public string CPU { get; set; }
    public string RAM { get; set; }
    public string SSD { get; set; }
    public string GPU { get; set; }
    
    public void ShowSpec() => 
        Console.WriteLine($"配置:{CPU} + {RAM} + {SSD} + {GPU}");
}

📜 2. 抽象建造者(组装规范)

public abstract class ComputerBuilder 
{
    protected Computer _computer = new Computer();
    
    // 必须实现的组装步骤(抽象方法)
    public abstract void InstallCPU();
    public abstract void InstallRAM(); 
    public abstract void InstallSSD();
    
    // 可选步骤(虚方法) 
    public virtual void InstallGPU() {} 
    
    // 获取最终产品 
    public Computer GetComputer() => _computer;
}

🔧 3. 具体建造者(两种配置方案)

方案一:办公配置

public class OfficeComputerBuilder : ComputerBuilder 
{
    public override void InstallCPU() => 
        _computer.CPU = "Intel i5";
    
    public override void InstallRAM() => 
        _computer.RAM = "16GB DDR4";
    
    public override void InstallSSD() => 
        _computer.SSD = "512GB NVMe";
    
    // 办公机不需要独立显卡(不重写InstallGPU)
}

方案二:游戏配置

public class GamingComputerBuilder : ComputerBuilder 
{
    public override void InstallCPU() => 
        _computer.CPU = "AMD Ryzen 9";
    
    public override void InstallRAM() => 
        _computer.RAM = "32GB DDR5";
    
    public override void InstallSSD() => 
        _computer.SSD = "1TB NVMe";
    
    // 游戏机需要显卡 
    public override void InstallGPU() => 
        _computer.GPU = "RTX 4080";
}

🎛️ 4. 指挥者(组装工程师)

public class ComputerEngineer 
{
    public Computer Build(ComputerBuilder builder)
    {
        builder.InstallCPU();
        builder.InstallRAM();
        builder.InstallSSD();
        builder.InstallGPU(); // 可选步骤 
        return builder.GetComputer();
    }
}

🛒 5. 使用示例

var engineer = new ComputerEngineer();
 
// 组装办公机 
var officeBuilder = new OfficeComputerBuilder();
var officePC = engineer.Build(officeBuilder);
officePC.ShowSpec(); // 输出:Intel i5 + 16GB DDR4 + 512GB NVMe 
 
// 组装游戏机 
var gameBuilder = new GamingComputerBuilder();
var gamePC = engineer.Build(gameBuilder); 
gamePC.ShowSpec(); // 输出:AMD Ryzen 9 + 32GB DDR5 + 1TB NVMe + RTX 4080 

🌟 抽象类实现的特点

强制与灵活结合

抽象方法强制必须实现的步骤(CPU/RAM/SSD)
虚方法提供可选步骤(GPU)

代码复用

公共的GetComputer()方法在抽象类中实现
子类只需要关注具体配置

扩展方便

新增「服务器配置」只需继承ComputerBuilder
旧代码完全不受影响

就像买组装电脑时:

抽象类是厂商提供的「标准配置单」(必须有哪些部件)
具体建造者是「不同档次的配置方案」
指挥者就是装机小哥,按固定流程帮你组装

🍕 使用抽象类实现披萨建造者模式(完整案例)

下面我们用抽象类来实现一个披萨建造系统,比接口实现更灵活:

1️⃣ 先定义产品(披萨类)

public class Pizza 
{
    public string Name { get; set; }
    public string Size { get; set; }
    public string CrustType { get; set; }
    public List<string> Toppings { get; } = new List<string>();
    public string Sauce { get; set; }
    public bool IsSpicy { get; set; }
    
    public void Display() 
    {
        Console.WriteLine($"
🍕 {Name} 披萨");
        Console.WriteLine($"尺寸: {Size}");
        Console.WriteLine($"饼底: {CrustType}");
        Console.WriteLine($"酱料: {Sauce}");
        Console.WriteLine($"辣度: {(IsSpicy ? "🌶️ 辣" : "不辣")}");
        Console.WriteLine($"配料: {string.Join(", ", Toppings)}");
    }
}

2️⃣ 抽象建造者(核心)

public abstract class PizzaBuilder 
{
    protected Pizza _pizza = new Pizza();
    
    // 必须实现的步骤(抽象方法)
    public abstract void SetName();
    public abstract void PrepareDough();
    public abstract void AddSauce();
    public abstract void AddToppings();
    
    // 可选步骤(虚方法)
    public virtual void AddSpices() {} 
    
    // 钩子方法(子类可覆盖)
    public virtual void SetSize() => _pizza.Size = "Medium";
    
    public Pizza GetPizza() => _pizza;
}

3️⃣ 具体建造者实现

意大利风味披萨

public class ItalianPizzaBuilder : PizzaBuilder 
{
    public override void SetName() => _pizza.Name = "意式经典";
    
    public override void PrepareDough()
    {
        _pizza.CrustType = "薄脆饼底";
        Console.WriteLine("--> 准备意式薄饼底");
    }
    
    public override void AddSauce()
    {
        _pizza.Sauce = "番茄蒜香酱";
        Console.WriteLine("--> 涂抹番茄蒜香酱");
    }
    
    public override void AddToppings()
    {
        _pizza.Toppings.AddRange(new[] { "意大利香肠", "橄榄", "蘑菇", "马苏里拉奶酪" });
        Console.WriteLine("--> 添加意式配料");
    }
    
    public override void SetSize() => _pizza.Size = "Large";
}

美式风味披萨

public class AmericanPizzaBuilder : PizzaBuilder 
{
    public override void SetName() => _pizza.Name = "美式至尊";
    
    public override void PrepareDough()
    {
        _pizza.CrustType = "芝心厚饼";
        Console.WriteLine("--> 准备美式厚饼底");
    }
    
    public override void AddSauce()
    {
        _pizza.Sauce = "BBQ酱";
        Console.WriteLine("--> 涂抹BBQ酱");
    }
    
    public override void AddToppings()
    {
        _pizza.Toppings.AddRange(new[] { "培根", "火腿", "洋葱", "青椒", "双倍奶酪" });
        Console.WriteLine("--> 添加美式豪华配料");
    }
    
    public override void AddSpices()
    {
        _pizza.IsSpicy = true;
        Console.WriteLine("--> 撒上墨西哥辣椒片");
    }
}

4️⃣ 指挥者(披萨师傅)

public class PizzaChef 
{
    public Pizza MakePizza(PizzaBuilder builder)
    {
        Console.WriteLine($"
开始制作 {builder.GetType().Name.Replace("Builder","")}...");
        
        builder.SetName();
        builder.SetSize();     // 调用钩子方法 
        builder.PrepareDough();
        builder.AddSauce();
        builder.AddToppings();
        builder.AddSpices();   // 可选步骤 
        
        Console.WriteLine("--> 烘烤20分钟");
        return builder.GetPizza();
    }
}

5️⃣ 使用示例

var chef = new PizzaChef();
 
// 制作意式披萨 
var italianBuilder = new ItalianPizzaBuilder();
var italianPizza = chef.MakePizza(italianBuilder);
italianPizza.Display();
 
// 制作美式披萨 
var americanBuilder = new AmericanPizzaBuilder();
var americanPizza = chef.MakePizza(americanBuilder); 
americanPizza.Display();

输出结果示例:

开始制作 ItalianPizza...
--> 准备意式薄饼底 
--> 涂抹番茄蒜香酱 
--> 添加意式配料 
--> 烘烤20分钟 
 
🍕 意式经典 披萨 
尺寸: Large 
饼底: 薄脆饼底 
酱料: 番茄蒜香酱 
辣度: 不辣 
配料: 意大利香肠, 橄榄, 蘑菇, 马苏里拉奶酪 
 
开始制作 AmericanPizza...
--> 准备美式厚饼底 
--> 涂抹BBQ酱 
--> 添加美式豪华配料 
--> 撒上墨西哥辣椒片 
--> 烘烤20分钟 
 
🍕 美式至尊 披萨 
尺寸: Medium 
饼底: 芝心厚饼 
酱料: BBQ酱 
辣度: 🌶️ 辣 
配料: 培根, 火腿, 洋葱, 青椒, 双倍奶酪 

🌟 抽象类实现的优势

灵活控制步骤

抽象方法强制必须实现的步骤
虚方法提供可选步骤(如AddSpices

默认实现

钩子方法SetSize()提供默认中号尺寸,子类可覆盖

日志记录

每个步骤添加了控制台输出,直观展示建造过程

业务扩展

很容易新增”素食披萨建造者”等变体
不需要修改现有建造逻辑

🏗️ 建造者模式:乐高积木式创建对象

🧩 什么是建造者模式?

想象你要组装一台电脑:

你不会直接从一堆零件开始胡乱拼装
而是按照说明书(建造者)一步步安装CPU、内存、硬盘
最后得到一台完整电脑

这就是建造者模式的核心思想——分步骤创建复杂对象

🧱 四个核心角色

产品(Product)
👉 最终要组装的完整对象(比如一台电脑/一部手机)

抽象建造者(Builder)
👉 组装说明书(规定有哪些零件要装)

abstract class 电脑组装说明书 {
    abstract void 装CPU();
    abstract void 装内存();
    abstract void 装硬盘();
    电脑 获取电脑();
}

具体建造者(ConcreteBuilder)
👉 具体品牌的组装方案

class 游戏电脑组装方案 : 电脑组装说明书 {
    void 装CPU() { 装i9处理器(); }
    void 装内存() { 装32G内存(); }
    //...其他具体实现 
}

指挥者(Director)
👉 组装工人(按固定流程组装)

class 装机师傅 { 
    电脑 组装电脑(电脑组装说明书 说明书) {
        说明书.装CPU();
        说明书.装内存();
        说明书.装硬盘();
        return 说明书.获取电脑();
    }
}

🎯 为什么用建造者模式?

适用场景:

✔️ 创建的对象很复杂(有很多零件)
✔️ 各零件的组装顺序是固定的
✔️ 同样的组装流程可以产生不同配置的产品

举个栗子🌰:

电脑商城:同样的装机流程,可以装游戏电脑/办公电脑
快餐店:同样的制作流程,可以做汉堡/鸡肉卷
汽车制造:同样的生产线,可以生产SUV/轿车

🔧 具体怎么用?(代码示例)

// 1. 产品:电脑 
class 电脑 {
    public string CPU { get; set; }
    public string 内存 { get; set; }
    public string 硬盘 { get; set; }
}
 
// 2. 抽象建造者 
abstract class 电脑建造者 {
    protected 电脑 _电脑 = new 电脑();
    public abstract void 安装CPU();
    public abstract void 安装内存();
    public abstract void 安装硬盘();
    public 电脑 获取电脑() => _电脑;
}
 
// 3. 具体建造者:游戏电脑 
class 游戏电脑建造者 : 电脑建造者 {
    public override void 安装CPU() => _电脑.CPU = "i9-13900K";
    public override void 安装内存() => _电脑.内存 = "32GB DDR5";
    public override void 安装硬盘() => _电脑.硬盘 = "2TB NVMe SSD";
}
 
// 4. 指挥者 
class 电脑装机员 {
    public 电脑 组装电脑(电脑建造者 建造者) {
        建造者.安装CPU();
        建造者.安装内存();
        建造者.安装硬盘();
        return 建造者.获取电脑();
    }
}
 
// 使用 
var 装机员 = new 电脑装机员();
var 我的电脑 = 装机员.组装电脑(new 游戏电脑建造者());

🌟 模式优点

组装过程标准化:所有电脑都按照相同流程组装
配置灵活多变:同样的流程可以生产不同配置的电脑
隐藏实现细节:用户不需要知道电脑怎么组装的

⚠️ 注意事项

适合零件多且组装顺序固定的场景
如果产品非常简单(只有2-3个零件),可能会显得”杀鸡用牛刀”
不同产品的零件要相似(比如都是电脑零件,不能突然混入汽车零件)

记住这个口诀:
“复杂对象分步造,同样流程不同貌” 🚀

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容