考虑两个构建器函数:一个用于构建购物收据,其中包含名称、日期和商品列表;另一个用于构建购物收据。第二个用于在收据中构建每个购物项目。简单的实现如下:
function Receipt(builder) {
return {
Name: builder.Name,
Date: builder.Date,
Items: builder.Items
};
}
function ReceiptBuilder() {
function WithName(name) {
this.Name = name;
return this;
}
function WithDate(dt) {
this.Date = dt;
return this;
}
function WithItem(item) {
this.Items = this.Items || [];
this.Items.push(item);
return this;
}
function build() {
return Receipt(this);
}
return {
WithName,
WithDate,
WithItem,
build
}
}
function Item(builder) {
return {
Type: builder.Type,
Price: builder.Price
};
}
function ItemBuilder() {
function WithType(type) {
this.Type = type;
return this;
}
function WithPrice(Price) {
this.Price = Price;
return this;
}
function build() {
return Item(this);
}
return {
WithPrice,
WithType,
build
}
}
然后我们可以按如下方式建立收据:
let receipt = ReceiptBuilder()
.WithName('Shopping')
.WithDate('01-01-01')
.WithItem(ItemBuilder().
WithPrice(1.99).
WithType('eggs').build())
.build()
是否可以重构以允许第二个构建器以某种方式“折叠”到第一个构建器中,以实现以下(或类似的)构建调用? IE。以某种方式“隐藏” ItemBuilder 会很好。
ReceiptBuilder()
.WithName('Shopping')
.WithDate('01-01-01')
.WithItem()
.WithPrice(1.99)
.WithType('eggs')
.build()
只需进行最少的更改,
WithItem()
方法就可以启动 ItemBuilder 并从中链接。需要有一些表明该项目已完成的标志,该标志将链接回 ReceiptBuilder。这是一个名为 endBuildingItem()
: 的方法
function WithItem() {
this.Items = this.Items || [];
const receiptBuilder = this;
return Object.assign(ItemBuilder(), {
endBuildingItem() {
receiptBuilder.Items.push(this.build());
return receiptBuilder;
}
});
}
const receipt1 = ReceiptBuilder()
.WithName('Shopping')
.WithDate('01-01-01')
.WithItem()
.WithPrice(1.99)
.WithType('eggs')
.endBuildingItem()
.build();
console.log(receipt1);
const receipt2 = ReceiptBuilder()
.WithName('Shopping')
.WithDate('01-01-01')
.WithItem()
.WithPrice(2.99)
.WithType('milk')
.endBuildingItem()
.WithItem()
.WithPrice(3.99)
.WithType('bread')
.endBuildingItem()
.build();
console.log(receipt2);
function Receipt(builder) {
return {
Name: builder.Name,
Date: builder.Date,
Items: builder.Items
};
}
function ReceiptBuilder() {
function WithName(name) {
this.Name = name;
return this;
}
function WithDate(dt) {
this.Date = dt;
return this;
}
function WithItem() {
this.Items = this.Items || [];
const receiptBuilder = this;
return Object.assign(ItemBuilder(), {
endBuildingItem() {
receiptBuilder.Items.push(this.build());
return receiptBuilder;
}
});
}
function build() {
return Receipt(this);
}
return {
WithName,
WithDate,
WithItem,
build
}
}
function Item(builder) {
return {
Type: builder.Type,
Price: builder.Price
};
}
function ItemBuilder() {
function WithType(type) {
this.Type = type;
return this;
}
function WithPrice(Price) {
this.Price = Price;
return this;
}
function build() {
return Item(this);
}
return {
WithPrice,
WithType,
build
}
}
.as-console-wrapper { max-height: 100% !important; }
另一种实现是将
endBuildingItem()
方法放入 ItemBuilder 中,并期望将 ReceiptBuilder 的实例传递给其中:
const receipt1 = ReceiptBuilder()
.WithName('Shopping')
.WithDate('01-01-01')
.WithItem()
.WithPrice(1.99)
.WithType('eggs')
.endBuildingItem()
.build();
console.log(receipt1);
const receipt2 = ReceiptBuilder()
.WithName('Shopping')
.WithDate('01-01-01')
.WithItem()
.WithPrice(2.99)
.WithType('milk')
.endBuildingItem()
.WithItem()
.WithPrice(3.99)
.WithType('bread')
.endBuildingItem()
.build();
console.log(receipt2);
function Receipt(builder) {
return {
Name: builder.Name,
Date: builder.Date,
Items: builder.Items
};
}
function ReceiptBuilder() {
function WithName(name) {
this.Name = name;
return this;
}
function WithDate(dt) {
this.Date = dt;
return this;
}
function WithItem() {
this.Items = this.Items || [];
return ItemBuilder(this);
}
function build() {
return Receipt(this);
}
return {
WithName,
WithDate,
WithItem,
build
}
}
function Item(builder) {
return {
Type: builder.Type,
Price: builder.Price
};
}
function ItemBuilder(receiptBuilder) {
function WithType(type) {
this.Type = type;
return this;
}
function WithPrice(Price) {
this.Price = Price;
return this;
}
function build() {
return Item(this);
}
function endBuildingItem() {
receiptBuilder.Items.push(this.build());
return receiptBuilder;
}
return {
WithPrice,
WithType,
build,
endBuildingItem,
}
}
.as-console-wrapper { max-height: 100% !important; }