java - JAVA中具有继承的生成器模式
问题描述
假设我有一个从另一个类扩展的类:
class Parent{
private String p1;
public void setP1(String p1){
this.p1 = p1;
}
}
class Child extends Parent{
private int c1;
public void setC1(int c1){
this.c1 = c1;
}
}
我使用 Builder Pattern 来创建 Parent 类的一个实例:
class ParentBuilder{
aParent(){ return new ParentBuilder()}
with(String p1){
this.p1 = p1;
}
public Parent build(){
Parent parent = new Parent();
parent.setP1(this.p1);
return parent;
}
}
我如何使用 Child 类的构建器模式来做类似的事情
aParent().with("test").build();
aChild().with(4).build();
aChild().with(4).with("test").build();
aChild().with("test").with(4).build();
解决方案
如果您有构建器所需的类层次结构,则应该使用它们自己的层次结构正确实现构建器。
正确的构建器实现不允许设置不属于构建对象的字段。例如,如果Parent
没有c1
字段,则不应允许通过设置它parentBuilder().withC1(val).build();
例如,如果您有以下对象层次结构:
GrandPa
|
Parent
|
/ \
Child1 Child2
按照以下代码创建构建器的层次结构是合理的:
与建设者的爷爷班:
public class GrandPa {
private Integer gp;
public void setGp(Integer gp) {
this.gp = gp;
}
public static class GrandPaBuilder extends
GrandPaBuilderWithResult<GrandPaBuilder, GrandPa> {
public static GrandPaBuilder grandPaBuilder() {
return new GrandPaBuilder();
}
@Override
public GrandPa build() {
GrandPa grandPa = new GrandPa();
grandPa.setGp(gp);
return grandPa;
}
}
public static abstract class GrandPaBuilderWithResult<T extends
GrandPaBuilderWithResult<T, R>, R extends GrandPa> {
Integer gp;
public T withGP(Integer gp) {
this.gp = gp;
return (T) this;
}
public abstract R build();
}
}
带有构建器的父类:
public class Parent extends GrandPa {
private String p;
public void setP(String p) {
this.p = p;
}
public static class ParentBuilder extends
ParentBuilderWithResult<ParentBuilder, Parent> {
public static ParentBuilder parentBuilder() {
return new ParentBuilder();
}
@Override
public Parent build() {
Parent parent = new Parent();
parent.setGp(gp);
parent.setP(this.p);
return parent;
}
}
public static abstract class ParentBuilderWithResult<T extends
ParentBuilderWithResult<T, R>, R extends Parent> extends
GrandPaBuilderWithResult<T, R> {
protected String p;
public T withP(String p) {
this.p = p;
return (T) this;
}
}
}
以及带有建设者的子类:
public class Child1 extends Parent {
private Double c1;
public void setC1(Double c1) {
this.c1 = c1;
}
public static class Child1Builder extends
ParentBuilderWithResult<Child1Builder, Child1> {
private Double c1;
public static Child1Builder child1Builder() {
return new Child1Builder();
}
public Child1Builder withC1(Double c1) {
this.c1 = c1;
return this;
}
@Override
public Child1 build() {
Child1 child1 = new Child1();
child1.setGp(gp);
child1.setP(p);
child1.setC1(this.c1);
return child1;
}
}
}
public class Child2 extends Parent {
private Double c2;
public void setC2(Double c2) {
this.c2 = c2;
}
public static class Child2Builder extends
ParentBuilderWithResult<Child2Builder, Child2> {
private Double c2;
public static Child2Builder child2Builder() {
return new Child2Builder();
}
public Child2Builder withC2(Double c2) {
this.c2 = c2;
return this;
}
@Override
public Child2 build() {
Child2 child2 = new Child2();
child2.setGp(gp);
child2.setP(p);
child2.setC2(this.c2);
return child2;
}
}
}
请注意在构建器中使用自绑定泛型始终只返回所需的对象引用。此实现是安全的,并且不允许通过构建器将错误放入您的代码中。
您可以通过以下方式使用它们:
GrandPa grandPa = GrandPa.GrandPaBuilder.grandPaBuilder().withGP(1).build();
Parent parent = Parent.ParentBuilder.parentBuilder().withGP(2).withP("p").build();
Child1 child1 = Child1.Child1Builder.child1Builder().withGP(3).withP("p1").withC1(1D).build();
Child2 child2 = Child2.Child2Builder.child2Builder().withGP(3).withP("p2").withC2(2D).build();
推荐阅读
- ruby-on-rails - 如何以collection_select rails形式将多个ID作为数组传递?
- python - 使用来自 csv 的 python 创建列表的字典
- sql-server - 总结国家活跃/不活跃
- php - Laravel Form:如何在不使用表单的情况下将隐藏信息传递给控制器
- linux - sed 脚本与仅使用 sed linux
- security - 谷歌海啸安全扫描仪没有按预期工作
- spring-boot - Spring Boot 管理端口的 ECS 健康检查问题
- c++ - 我是 C++ 编程新手,这些代码有什么区别,我应该使用哪一个?
- microsoft-graph-api - 使用 Graph API 在 MS Teams 上发送/回复消息时出现未知错误
- antd - Ant Design 动态表单验证