Skip to content

Head First 设计模式 16-生成器模式

🏷️ 《Head First 设计模式》

生成器模式(Builder Pattern)封装一个产品的构造过程,并允许按步骤构造

这种模式在 ORMObject Relational Mapping 对象关系映射)框架的查询中经常能够遇到,很多框架都会提供类似 SqlBuilder 的功能。

书中以“主题公园”为例,通过生成器创建你的行程计划。其类图如下:

客户端采用类似下面的方式,按照生成器的规则创建假期计划。

csharp
AbstarctBuilder builder = new VacationBuilder();
builder.BuildDay(new DateTime(2020, 1, 1))
    .AddHotel("葛雷巴旅馆")
    .AddReservation("棒球比赛")
    .AddSpecialEvent("拨打接听付费电话")
    .AddTickets(new string[] { "《美丽人生》电影票", "张学友演唱会票" });
builder.BuildDay(new DateTime(2020, 1, 2))
    .AddHotel("葛雷巴旅馆")
    .AddReservation("棒球比赛决赛")
    .AddSpecialEvent("继续拨打接听付费电话");
Console.WriteLine(builder.GetVacationPlanner());

优点

  • 将一个复杂对象的创建过程封装起来。
  • 允许对象通过多个步骤来创建,并且可以改变过程(这和只有一个步骤的工厂模式不同)。
  • 向客户隐藏产品内部的实现。
  • 产品的实现可以被替换,因为客户只看到一个抽象的接口。

用途和缺点

  • 经常被用来创建组合接口。
  • 与工厂模式相比,采用生成器模式创建对象的客户,需要具备更多的领域知识。

示例代码

AbstarctBuilder

抽象的生成器

csharp
interface AbstarctBuilder
{
    AbstarctBuilder BuildDay(DateTime day);
    AbstarctBuilder AddHotel(string hotel);
    AbstarctBuilder AddReservation(string reservation);
    AbstarctBuilder AddSpecialEvent(string specialEvent);
    AbstarctBuilder AddTickets(string[] tickets);
    string GetVacationPlanner();
}

VacationBuilder

具体的生成器

csharp
class VacationBuilder : AbstarctBuilder
{
    List<Vacation> _vacations = new List<Vacation>();
    Vacation _currentVacation;

    public AbstarctBuilder BuildDay(DateTime day)
    {
        _currentVacation = new Vacation();
        _vacations.Add(_currentVacation);
        _currentVacation.Day = day;
        return this;
    }

    public AbstarctBuilder AddHotel(string hotel)
    {
        _currentVacation.Hotels.Add(hotel);
        return this;
    }

    public AbstarctBuilder AddReservation(string reservation)
    {
        _currentVacation.Reservations.Add(reservation);
        return this;
    }

    public AbstarctBuilder AddSpecialEvent(string specialEvent)
    {
        _currentVacation.SpecialEvents.Add(specialEvent);
        return this;
    }

    public AbstarctBuilder AddTickets(string[] tickets)
    {
        _currentVacation.Tickets.AddRange(tickets);
        return this;
    }

    public string GetVacationPlanner()
    {
        return JsonConvert.SerializeObject(_vacations);
    }
}

Client

客户端测试代码

csharp
AbstarctBuilder builder = new VacationBuilder();
builder.BuildDay(new DateTime(2020, 1, 1))
    .AddHotel("葛雷巴旅馆")
    .AddReservation("棒球比赛")
    .AddSpecialEvent("拨打接听付费电话")
    .AddTickets(new string[] { "《美丽人生》电影票", "张学友演唱会票" });
builder.BuildDay(new DateTime(2020, 1, 2))
    .AddHotel("葛雷巴旅馆")
    .AddReservation("棒球比赛决赛")
    .AddSpecialEvent("继续拨打接听付费电话");
Console.WriteLine(builder.GetVacationPlanner());