🚀24个C#设计模式目录    🍺源码地址

概述

对于今天大部分的的手机📱厂商而言,📱的制造需要各个供应商提供零部件,然后再按照自己的设计组装完成。

以 一加7T 这台机型举例:

部件 供应商 产品
SOC 高通 骁龙 855 Plus
屏幕 三星 6.55英寸的90 Hz流体屏幕
主摄镜头 索尼 4800万像素的IMX 586
电池 欣旺达电子 3800 mAh锂电池

对于一加来说,并不需要知道这些零部件的生产过程,而是关注如何将零部件构建成📱的过程,最终生产出一部完整的📱产品。对于用户来说,不需要关注📱如何一步步生产出来,只需要指定机型,就可以购买手机产品。

建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

建造者模式将客户端与包含多个部件的复杂对象的创建过程分离,即使在相同的流水线,更换零部件就可以生产出不同的产品。客户端无须知道复杂对象的内部组成部分与装配方式,只需知道所建造者的类型即可。

使用频率:★★★☆☆

结构与实现

在建造者模式中,包含4个角色:

  • Builder(抽象建造者)
  • ConcreteBuilder(具体建造者)
  • Product(产品)
  • Director(指挥者)

在抽象建造者Builder中,有两类方法,一类是BuildPartX()用于构建各个部件,另一类方法是GetResult()用于获取创建好的复杂对象。Builder既可以做接口,也可做抽象类,实现部分方法,比如GetResult()

指挥者Director负责安排复杂对象的建造次序,客户端一般只需要与指挥者交互。

以一加手机举例,一加作为指挥者,具体建造者包括一加6T和一加7T两款手机的建造者,实现了PhoneBuilder,使用了不同BuildSOCBuildScreen等方法选用不同的零部件,但是OnePlus使用相同Construct装配流程,可以生产出两种不同型号的📱。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Product
class Phone
{
// Part1
public string Name { get; set; }
// Part2
public string SOC { get; set; }
// Part3
public string Screen { get; set; }
// Part4
public string Battery { get; set; }
// Part5
public string Camera { get; set; }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Builder
abstract class PhoneBuilder
{
// 创建产品对象
protected Phone phone = new Phone();
public abstract void BuildName();
public abstract void BuildSOC();
public abstract void BuildScreen();
public abstract void BuildCamera();
public abstract void BuildBattery();

// 获取产品对象 GetResult
public Phone GetPhone()
{
return phone;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// ConcreteBuilder
class OnePlus6TBuilder : PhoneBuilder
{
public override void BuildName()
{
this.phone.Name = "OnePlus 6T";
}
public override void BuildSOC()
{
this.phone.SOC = "Qualcomm Snapdragon 845";
}
public override void BuildScreen()
{
this.phone.Screen = "6.41-inch 19.5:9 Optic AMOLED";
}
public override void BuildCamera()
{
this.phone.Camera = "Sony IMX 519";
}
public override void BuildBattery()
{
this.phone.Battery = "3700 mAh lithium battery";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// ConcreteBuilder
class OnePlus7TBuilder : PhoneBuilder
{
public override void BuildName()
{
this.phone.Name = "OnePlus 7T";
}
public override void BuildSOC()
{
this.phone.SOC = "Qualcomm Snapdragon 855 Plus";
}
public override void BuildScreen()
{
this.phone.Screen = "Samsung 6.55-inch 90Hz Fluid Display";
}
public override void BuildCamera()
{
this.phone.Camera = "Sony IMX 586";
}
public override void BuildBattery()
{
this.phone.Battery = "3800 mAh lithium battery";
}
}

Director中的Construct()方法定义了BuildPartX()的调用次序,提供了一个流程模板。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Director
class OnePlus
{
private PhoneBuilder phoneBuilder;

public void SetPhoneBuilder(PhoneBuilder phoneBuilder)
{
this.phoneBuilder = phoneBuilder;
}
public Phone Construct()
{
phoneBuilder.BuildName();
phoneBuilder.BuildSOC();
phoneBuilder.BuildScreen();
phoneBuilder.BuildCamera();
phoneBuilder.BuildBattery();
return phoneBuilder.GetPhone();
}
}

客户端调用时,需要为一加指定机型(具体建造者),就可以获得具体的📱产品。指定具体建造者实例也可以使用配置文件等方法注入。

1
2
3
4
5
6
7
8
9
10
11
12
static void Main(string[] args)
{
OnePlus onePlus = new OnePlus();
onePlus.SetPhoneBuilder(new OnePlus7TBuilder());
//onePlus.SetPhoneBuilder(new OnePlus6TBuilder());
Phone phone = onePlus.Construct();
Console.WriteLine(phone.Name);
Console.WriteLine(phone.SOC);
Console.WriteLine(phone.Screen);
Console.WriteLine(phone.Camera);
Console.WriteLine(phone.Battery);
}

在建造者模式中,Director角色可以与Builder角色合并,也就是将Director的Construct()方法直接写入Builder的GetResult()方法中。这种实现会简化了系统,且不影响灵活性和扩展性,但是加重了Builder的职责,对于Construct()方法较为复杂的场景不适用。

优缺点

优点:

  1. 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
  2. 可以很方便地增加或更换具体建造者。
  3. 将复杂的产品创建步骤分解在不同的方法中,使得创建过程更加清晰,控制也更为方便。

缺点:

  1. 建造者模式要求所创建的产品有较多的共同点,组成成分相似,如果产品间差异较大则不适合建造者模式。
  2. 如果产品内部组成变化复杂,可能会需要定义很多具体建造者类来实现这种变化,导致系统变的很庞大,增加系统理解难度和运行成本。

适用场景

  • 需要生产的产品有复杂的内部结构,这些产品对象通常包含多个成员变量。
  • 需要生产的产品对象熟悉相互依赖,需要指定其生产顺序。
  • 对象的创建过程独立于创建该对象的类。
  • 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。