gpt4 book ai didi

c++ - 如何实现嵌套流畅的接口(interface)?

转载 作者:搜寻专家 更新时间:2023-10-31 01:37:00 24 4
gpt4 key购买 nike

我的任务是为一个由其他类组成的类实现流畅的接口(interface)。假设我们有一个类:

class Pizza {
int price, size;
}
class Foo {
string name;
Pizza p1, p2;
}

我想使用如下代码:

Foo f = FooBuilder().setName("foo")
.settingP1().setPrice(5).setSize(1)
.settingP2().setPrice(2)
.build();

但我也想禁止这样的代码:

Foo f = FooBuilder().setName("foo").setPrice(5);

我想到了一个继承自 FooBuilder 的类,该类在调用 .settingP1() 后返回,但我不确定该怎么做。请注意,当我结束指定 Pizza 对象时,我不想编写 .build()

编辑:也许我应该提到当我写 .settingP2().setPrice(2) 而没有写 .setSize(sth) 我的意思是 size 会只有默认值。无论是否指定所有属性,我都希望能够“跳转”到下一个对象

EDIT2:我知道如何为具有基本类型字段的类实现构建器模式和流畅的接口(interface)。问题是我想要代码

Foo f = FooBuilder().setName("foo").setPrice(5);

不编译。也许不可能编写这样的构建器。

最佳答案

如果您不介意,我会用 Java 为您的问题编写解决方案,希望您能够在 C++ 中应用它而不会出现任何问题。

您有 2 个选择。

  1. 更详细的 DSL(我不想再称你的问题为 Builder,而是 Fluent API 或 DSL - Domain Specific Language,因为它为它定义了语法规则),实现更简单
  2. 或更简单的 DSL(正是您编写的内容),在实现中有一个小技巧。

对于选项 #1,您的用法如下所示:

new FooBuilder().setName("Foo")
.settingP1().setPrice(5).setSize(1).end()
.settingP2().setPrice(2).end()
.build();

注意其他方法 end()。 Java 中的相应代码如下所示:

public class FooBuilder {
public FooBuilder setName(String name) {
// Store the name
return this;
}
public PizzaBuilder settingP1() {
return new PizzaBuilder(pizza1, this);
}
public PizzaBuilder settingP2() {
return new PizzaBuilder(pizza2, this);
}
public Foo build() {
// return Foo build using stored information
}
}

public class PizzaBuilder {
private final Pizza pizza;
private final FooBuilder foo;
// Constructor
public PizzaBuilder(Pizza pizza, FooBuilder foo) {
this.pizza = pizza;
this.foo = foo;
}
public PizzaBuilder setPrice(int price) {
// update pizza price
return this;
}
public PizzaBuilder setSize(int size) {
// update pizza size
return this;
}
// With this method you return to parent, and you can set second pizza.
public FooBuilder end() {
return foo;
}
}

现在对于选项 #2,我将对您的问题进行另一种概括,以允许定义任意数量的比萨饼。我还会省略 set 前缀,这对于 DSL 来说并不常见:

new FooBuilder().name("Foo")
.addPizzaWith().price(5).size(1)
.addPizzaWith().price(2)
.build();

现在的实现看起来像这样:

public class FooBuilder {
public FooBuilder(String name) {
// Store name
return this;
}
public PizzaBuilder addPizzaWith() {
Pizza pizza = createAndStorePizza(); // Some private method to do what is says
return new PizzaBuilder(pizza, this);
}
public Foo build() {
// Build and return the Foo using stored data
}
}

public class PizzaBuilder {
private final Pizza pizza;
private final FooBuilder foo;
public PizzaBuilder(Pizza pizza, FooBuilder foo) {
this.pizza = pizza;
this.foo = foo;
}
public PizzaBuilder price(int value) {
// Store price value
return this;
}
public PizzaBuilder size(int value) {
// Store size value
return this;
}
// This method does the trick - it terminates first pizza specification,
// and delegates entering second (or any other) pizza specification to
// the parent FooBuilder.
public PizzaBuilder addPizzaWith() {
return foo.addPizzaWith();
}
// Another similar trick with allowing to call build directly on Pizza
// specification
public Foo build() {
return foo.build();
}
}

有一个值得注意的属性——循环依赖。 FooBuilder 必须知道 PizzaBuilder,PizzaBuilder 必须知道 FooBuilder。在 Java 中,这不是问题。如果我没记错的话,你也可以通过首先声明使用前向声明或其他类型。

对于 Java 中的第二个示例,引入具有方法 build()addPizzaWith() 的接口(interface)通常也是有益的,这两个类都实现了这两个方法。所以你可以,例如循环添加比萨饼没有任何问题。

关于c++ - 如何实现嵌套流畅的接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34864311/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com