如何解决有没有办法用“限制性 API”来实现构建器模式而不会太冗长
在设计组件 X
时,我想使用允许指定 A
、B
和 C
的构建器模式出于可用性目的,以流畅的方式显示值。
出于类似的可用性目的,我想使任何使用 X 的 API 的开发人员都无法(API 方面)指定 A
、B
或 C
更多不止一次。
但是,由于 API 用户反馈的时间成本,我无法接受构建器的运行时失败,并且允许该值被第二次调用覆盖在功能上没有意义,因此也不能接受.
我为这个问题找到的唯一解决方案是创建 8 个(!)构建器接口,每个接口都有自己的此类构建器实现:
IHavenothing<X>
IHaveA<X>
IHaveB<X>
IHaveC<X>
IHaveAAndB<X>
IHaveAAndC<X>
IHaveBAndC<X>
IHaveAAndBAndC<X>
对于这样一个简单的构建器来说,这有点矫枉过正,但想不出比这更冗长的东西了。
是否有任何模式可以减轻这种构建器的冗长?
谢谢
解决方法
如果您强制对元素进行某种排序,则可以使用更少的接口。通过这样做,您不需要为所有 A+B、A+C 和 B+C 提供接口。
另一个技巧是只创建 1 个构建器实现类来实现所有接口,API 用户可能无法访问这些接口。
像这样:
interface ResultBuilder {
static ABuilder builder() {
return new ResultBuilderImpl();
}
interface ABuilder {
BBuilder a(A a);
}
interface BBuilder {
CBuilder b(B b);
}
interface CBuilder {
ResultBuilder c(C c);
}
Result build();
}
和实现:
class ResultBuilderImpl implements ResultBuilder,ResultBuilder.ABuilder,ResultBuilder.BBuilder,ResultBuilder.CBuilder {
private A a;
private B b;
private C c;
public BBuilder a(A a) {
this.a = a;
return this;
}
public CBuilder b(B b) {
this.b = b;
return this;
}
public ResultBuilder c(C c) {
this.c = c;
return this;
}
public Result build() {
return new Result(a,b,c);
}
}
用法:
Result result = ResultBuilder.builder()
.a(new A())
.b(new B())
.c(new C())
.build();
,
Java 在解析类型时没有回溯(没有复杂的类型推断),但您可以构建一个构建器而不受限制以特定顺序设置值。
定义类型以在确定参数时进行注释:
interface A {}
interface B {}
interface C {}
定义类型以在参数未确定时进行注释:
interface NA {}
interface NB {}
interface NC {}
构建器看起来像:
static class Builder<R,S,T> {
int _a = 0;
int _b = 0;
int _c = 0;
R r;
S s;
T t;
Builder(int _a,int _b,int _c,R r,S s,T t) {
this._a = _a;
this._b = _b;
this._c = _c;
this.r = r;
this.s = s;
this.t = t;
}
static <R extends NA,T> Builder<A,T> A(Builder<R,T> z,int n) {
return new Builder<>(n,z._b,z._c,null,null);
}
static <R,S extends NB,T> Builder<R,B,T> B(Builder<R,int n) {
return new Builder<>(z._a,n,T extends NC> Builder<R,C> C(Builder<R,null);
}
static Builder<NA,NB,NC> builder() {
return new Builder<>(0,null);
}
<M,N> M set(BiFunction<Builder<? extends R,? extends S,? extends T>,N,M> k,N n) {
return k.apply(this,n);
}
void build() {
System.out.printf("<%d,%d,%d>%n",_a,_b,_c);
}
}
什么时候:
-
_a
,_b
,... 是每个输入参数。 -
r
,s
,... 是在确定或未确定时执行的类型注释。 - 构造函数。
-
A
,B
,... 是将非固定注释转换为固定注释的静态限制。 -
builder
构造未固定的初始值。 -
set
发挥作用,在类型注释中启用回溯。 -
build
在这种情况下打印值。
现在我们可以按任意顺序设置值
builder().set(Builder::B,2).set(Builder::A,1).build();
builder().set(Builder::A,1).set(Builder::C,3).set(Builder::B,2).build();
带输出
<1,2,0>
<1,3>
但是如果你尝试设置两次
,好吧,您可以每一步实现一个类或接口,并允许在每一步创建 X
。像这样:
class X { }
interface BuildStep {
X build();
}
interface StepC extends BuildStep {
BuildStep c(String param);
}
interface StepB extends StepC {
StepC b(String param);
}
interface StepA extends StepB {
StepB a(String param);
}
class XBuilder implements StepA {
@Override
public StepC b(String param) {
//handle param
return this;
}
@Override
public BuildStep c(String param) {
//handle param
return this;
}
@Override
public StepB a(String param) {
//handle param
return this;
}
@Override
public X build() {
//build the new X
return new X();
}
static XBuilder builder() {
return new XBuilder ();
}
}
这样你的案例就会看起来像这样(将强制执行调用顺序,即 A -> B -> C -> X,同时能够在该链中的任何位置开始):
X x;
//IHaveNothing<X>
x = XBuilder.builder().build();
//IHaveA<X>
x = XBuilder.builder().a(param).build();
//IHaveB<X>
x = XBuilder.builder().b(param).build();
//IHaveC<X>
x = XBuilder.builder().c(param).build();
//IHaveAAndB<X>
x = XBuilder.builder().a(param).b(param).build();
//IHaveAAndC<X>
x = XBuilder.builder().a(param).c(param).build();
//IHaveBAndC<X>
x = XBuilder.builder().b(param).c(param).build();
//IHaveAAndBAndC<X>
x = XBuilder.builder().a(param).b(param).c(param).build();
但是,这是不允许的:
//those make the compiler cry and slap you in the face :)
x = XBuilder.builder().c(param).a(param).b(param).build();
x = XBuilder.builder().a(param).a(param).b(param).build();
,
IHaveNothing 仅包含 ProvideA(...)
仅 IHaveA 和 ProvideB(...)
IHaveAB 仅包含 ProvideC(...)
仅带有 Build() 的 IHaveABC
应该足够了还是我没有完全理解您的要求?不过,这种设计会强制执行命令。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。