多态对象层次结构的构建器模式:Java可能吗?

多态对象层次结构的构建器模式:Java可能吗?,java,design-patterns,builder,Java,Design Patterns,Builder,我有一个接口层次结构,子接口实现父接口。我希望使用不可变对象,因此我希望设计方便地构造这些对象的Builder类。但是,我有许多Child接口,我不想在每种类型的子生成器中重复构建Parents的代码 因此,假设以下定义: public interface Parent { public Long getParentProperty(); } public interface Child1 extends Parent { public Integer getChild1Pro

我有一个接口层次结构,子接口实现父接口。我希望使用不可变对象,因此我希望设计方便地构造这些对象的
Builder
类。但是,我有许多
Child
接口,我不想在每种类型的子生成器中重复构建
Parent
s的代码

因此,假设以下定义:

public interface Parent {
    public Long getParentProperty();
}

public interface Child1 extends Parent {
    public Integer getChild1Property(); 
}

public interface Child2 extends Parent {
    public String getChild2PropertyA();
    public Object getChild2PropertyB();
}
如何有效地实现构建器
Child1Builder
Child2Builder
?它们应支持以下操作:

Child1 child1 = Child1Builder.newChild1().withChild1Property(5).withParentProperty(10L);

我不想为每个子生成器实现一个特殊的
withParentProperty

编辑以将第二个属性添加到
Child2
,以澄清这不能通过简单的泛型实现。我不是在寻找一种方法来组合
Child1
Child2
——我在寻找一种方法来实现一个
Builder
系统,它不会重复为每个子类构建父类的工作


谢谢你的帮助

使用泛型,如下所示:

public interface Parent {
    public Long getParentProperty();
}

public interface Child<T> {
    public T getChildProperty(); 
}
公共接口父级{
公共长getParentProperty();
}
公共接口子项{
公共T getChildProperty();
}

然后用
Child
代替Child1,用
Child2代替Child2,用
Child
我想象的解决方案就像CRTP。您可以定义一个基类来处理与父类相关的初始化,但是您仍然会发现两个样板文件
getParent()
getThis()
方法在每个派生的与子类相关的构建器类中重复太多

看一看:

abstract class ParentBase implements Parent
{
  @Override
  public final Long getParentProperty()
  {
      return parentProperty_;
  }


  protected void setParentProperty(Long value)
  {
      parentProperty_ = value;
  }


  private Long parentProperty_;
}


abstract class ParentBuilder<T extends ParentBuilder<T>>
{
  T withParentProperty(Long value)
  {
      getParent().setParentProperty(value);
      return getThis();
  }


  protected abstract ParentBase getParent();


  protected abstract T getThis();
}


final class ConcreteChild1 extends ParentBase implements Child1
{
  @Override
  public Integer getChild1Property()
  {
      return childProperty_;
  }


  public void setChild1Property(Integer value)
  {
      childProperty_ = value;
  }


  private Integer childProperty_;
}


final class Child1Builder extends ParentBuilder<Child1Builder>
{
  public Child1Builder()
  {
     pending_ = new ConcreteChild1();
  }


  public Child1Builder withChild1Property(Integer value)
  {
      pending_.setChild1Property(value);
      return this;
  }


  @Override
  protected ParentBase getParent()
  {
      return pending_;
  }


  @Override
  protected Child1Builder getThis()
  {
      return this;
  }


  private final ConcreteChild1 pending_;
}
抽象类ParentBase实现父类
{
@凌驾
公共最终长getParentProperty()
{
返回parentProperty;
}
受保护的void setParentProperty(长值)
{
parentProperty=值;
}
私人长父母财产;
}
抽象类父生成器
{
T withParentProperty(长值)
{
getParent().setParentProperty(值);
返回getThis();
}
受保护的抽象ParentBase getParent();
保护抽象T getThis();
}
最后一个类ConcreteChild1扩展了ParentBase,实现了Child1
{
@凌驾
公共整数getChild1Property()
{
归还儿童财产;
}
public void setChild1属性(整数值)
{
childProperty=值;
}
私有整数childProperty;
}
最终类Child1Builder扩展了ParentBuilder
{
公共Child1Builder()
{
挂起=新的ConcreteChild1();
}
具有Child1属性(整数值)的公共Child1生成器
{
挂起。setChild1属性(值);
归还这个;
}
@凌驾
受保护的ParentBase getParent()
{
返回待定;
}
@凌驾
受保护的儿童1生成器getThis()
{
归还这个;
}
私人最终子女1待定;
}
如您所见,
ParentBuilder
类型期望与派生类型协作,以允许它返回正确类型的实例。它自己的
this
引用不会到期,因为
ParentBuilder
中的
this
类型当然是
ParentBuilder
,而不是要维护“流畅”调用链接的
Child1Builder


我把“
getThis()
技巧”归功于。

没有构建器的情况下可能会这样吗?:

interface P {
    public Long getParentProperty();
}
interface C1 extends P {
    public Integer getChild1Property();
}
interface C2 extends P {
    public String getChild2PropertyA();
    public Object getChild2PropertyB();
}
abstract class PABC implements P {
    @Override public final Long getParentProperty() {
        return parentLong;
    }
    protected Long parentLong;
    protected PABC setParentProperty(Long value) {
        parentLong = value;
        return this;
    }
}
final class C1Impl extends PABC implements C1 {
    protected C1Impl setParentProperty(Long value) {
        super.setParentProperty(value);
        return this;
    }
    @Override public Integer getChild1Property() {
        return n;
    }
    public C1Impl setChild1Property(Integer value) {
        n = value;
        return this;
    }
    private Integer n;
}
final class C2Impl extends PABC implements C2 {
    private String string;
    private Object object;

    protected C2Impl setParentProperty(Long value) {
        super.setParentProperty(value);
        return this;
    }
    @Override public String getChild2PropertyA() {
    return string;
    }

    @Override public Object getChild2PropertyB() {
        return object;
    }
    C2Impl setChild2PropertyA(String string) {
        this.string=string;
        return this;
    }
    C2Impl setChild2PropertyB(Object o) {
        this.object=o;
        return this;
    }
}
public class Myso9138027 {
    public static void main(String[] args) {
        C1Impl c1 = new C1Impl().setChild1Property(5).setParentProperty(10L);
        C2Impl c2 = new C2Impl().setChild2PropertyA("Hello").setParentProperty(10L).setChild2PropertyB(new Object());
    }
}
包SO913802;
导入java.util.*;
导入so9138027take2.C2.name;
接口P{
公共对象getParentProperty(名称);
枚举名称{
i(Integer.class)、d(Double.class)、s(String.class);
名称(类clazz){
this.clazz=clazz;
}
最后一节课;
}
}
接口C1扩展了P{
公共对象getChildProperty(名称);
枚举名称{
a(Integer.class)、b(Double.class)、c(String.class);
名称(类clazz){
this.clazz=clazz;
}
最后一节课;
}
}
接口C2扩展到P{
公共对象getChildProperty(名称);
枚举名称{
x(Integer.class)、y(Double.class)、z(String.class);
名称(类clazz){
this.clazz=clazz;
}
最后一节课;
}
}
抽象类PABCImmutable实现了P{
公共PABCImmutable(PABC父级){
parentNameToValue=Collections.unmodifiableMap(parent.parentNameToValue);
}
@重写公共最终对象getParentProperty(名称){
返回parentNameToValue.get(name);
}
公共字符串toString(){
返回parentNameToValue.toString();
}
最终映射parentNameToValue;
}
抽象类PABC实现了P{
@重写公共最终对象getParentProperty(名称){
返回parentNameToValue.get(name);
}
受保护的PABC setParentProperty(名称、对象值){
if(name.clazz.isInstance(value))parentNameToValue.put(name,value);
其他的
抛出新的RuntimeException(“值对“+name”无效);
归还这个;
}
公共字符串toString(){
返回parentNameToValue.toString();
}
EnumMap parentNameToValue=新的EnumMap(P.Names.class);
}
最后一个类C1Immutable扩展了PABCImmutable实现C1{
公共c1不可变(c1 impl c1){
超级(c1);
nameToValue=Collections.unmodifiableMap(c1.nameToValue);
}
@重写公共对象getChildProperty(C1.name){
返回nameToValue.get(name);
}
公共字符串toString(){
返回super.toString()+nameToValue.toString();
}
最终地图名称和价值;
}
最后一个类C1Impl扩展了PABC实现C1{
@重写公共对象getChildProperty(C1.name){
返回nameToValue.get(name);
}
公共对象setChildProperty(C1.Names名称、对象值){
if(name.clazz.isInstance(value))nameToValue.put(name,value);
其他的
扔
interface P {
    public Long getParentProperty();
}
interface C1 extends P {
    public Integer getChild1Property();
}
interface C2 extends P {
    public String getChild2PropertyA();
    public Object getChild2PropertyB();
}
abstract class PABC implements P {
    @Override public final Long getParentProperty() {
        return parentLong;
    }
    protected Long parentLong;
    protected PABC setParentProperty(Long value) {
        parentLong = value;
        return this;
    }
}
final class C1Impl extends PABC implements C1 {
    protected C1Impl setParentProperty(Long value) {
        super.setParentProperty(value);
        return this;
    }
    @Override public Integer getChild1Property() {
        return n;
    }
    public C1Impl setChild1Property(Integer value) {
        n = value;
        return this;
    }
    private Integer n;
}
final class C2Impl extends PABC implements C2 {
    private String string;
    private Object object;

    protected C2Impl setParentProperty(Long value) {
        super.setParentProperty(value);
        return this;
    }
    @Override public String getChild2PropertyA() {
    return string;
    }

    @Override public Object getChild2PropertyB() {
        return object;
    }
    C2Impl setChild2PropertyA(String string) {
        this.string=string;
        return this;
    }
    C2Impl setChild2PropertyB(Object o) {
        this.object=o;
        return this;
    }
}
public class Myso9138027 {
    public static void main(String[] args) {
        C1Impl c1 = new C1Impl().setChild1Property(5).setParentProperty(10L);
        C2Impl c2 = new C2Impl().setChild2PropertyA("Hello").setParentProperty(10L).setChild2PropertyB(new Object());
    }
}
package so9138027take2;
import java.util.*;
import so9138027take2.C2.Names;
interface P {
    public Object getParentProperty(Names name);
    enum Names {
        i(Integer.class), d(Double.class), s(String.class);
        Names(Class<?> clazz) {
            this.clazz = clazz;
        }
        final Class<?> clazz;
    }
}
interface C1 extends P {
    public Object getChildProperty(Names name);
    enum Names {
        a(Integer.class), b(Double.class), c(String.class);
        Names(Class<?> clazz) {
            this.clazz = clazz;
        }
        final Class<?> clazz;
    }
}
interface C2 extends P {
    public Object getChildProperty(Names name);
    enum Names {
        x(Integer.class), y(Double.class), z(String.class);
        Names(Class<?> clazz) {
            this.clazz = clazz;
        }
        final Class<?> clazz;
    }
}
abstract class PABCImmutable implements P {
    public PABCImmutable(PABC parent) {
        parentNameToValue = Collections.unmodifiableMap(parent.parentNameToValue);
    }
    @Override public final Object getParentProperty(Names name) {
        return parentNameToValue.get(name);
    }
    public String toString() {
        return parentNameToValue.toString();
    }
    final Map<Names, Object> parentNameToValue;
}
abstract class PABC implements P {
    @Override public final Object getParentProperty(Names name) {
        return parentNameToValue.get(name);
    }
    protected PABC setParentProperty(Names name, Object value) {
        if (name.clazz.isInstance(value)) parentNameToValue.put(name, value);
        else
            throw new RuntimeException("value is not valid for " + name);
        return this;
    }
    public String toString() {
        return parentNameToValue.toString();
    }
    EnumMap<Names, Object> parentNameToValue = new EnumMap<Names, Object>(P.Names.class);
}
final class C1Immutable extends PABCImmutable implements C1 {
    public C1Immutable(C1Impl c1) {
        super(c1);
        nameToValue =  Collections.unmodifiableMap(c1.nameToValue);
    }
    @Override public Object getChildProperty(C1.Names name) {
        return nameToValue.get(name);
    }
    public String toString() {
        return super.toString() + nameToValue.toString();
    }
    final Map<C1.Names, Object> nameToValue;
}
final class C1Impl extends PABC implements C1 {
    @Override public Object getChildProperty(C1.Names name) {
        return nameToValue.get(name);
    }
    public Object setChildProperty(C1.Names name, Object value) {
        if (name.clazz.isInstance(value)) nameToValue.put(name, value);
        else
            throw new RuntimeException("value is not valid for " + name);
        return this;
    }
    public String toString() {
        return super.toString() + nameToValue.toString();
    }
    EnumMap<C1.Names, Object> nameToValue = new EnumMap<C1.Names, Object>(C1.Names.class);
}
final class C2Immutable extends PABCImmutable implements C2 {
    public C2Immutable(C2Impl c2) {
        super(c2);
        this.nameToValue = Collections.unmodifiableMap(c2.nameToValue);
    }
    @Override public Object getChildProperty(C2.Names name) {
        return nameToValue.get(name);
    }
    public String toString() {
        return super.toString() + nameToValue.toString();
    }
    final Map<C2.Names, Object> nameToValue;
}
final class C2Impl extends PABC implements C2 {
    @Override public Object getChildProperty(C2.Names name) {
        return nameToValue.get(name);
    }
    public Object setChildProperty(C2.Names name, Object value) {
        if (name.clazz.isInstance(value)) {
            nameToValue.put(name, value);
        } else {
            System.out.println("name=" + name + ", value=" + value);
            throw new RuntimeException("value is not valid for " + name);
        }
        return this;
    }
    public String toString() {
        return super.toString() + nameToValue.toString();
    }
    EnumMap<C2.Names, Object> nameToValue = new EnumMap<C2.Names, Object>(C2.Names.class);
}
public class So9138027take2 {
    public static void main(String[] args) {
        Object[] parentValues = new Object[] { 1, 2., "foo" };
        C1Impl c1 = new C1Impl();
        Object[] c1Values = new Object[] { 3, 4., "bar" };
        for (P.Names name : P.Names.values())
            c1.setParentProperty(name, parentValues[name.ordinal()]);
        for (C1.Names name : C1.Names.values())
            c1.setChildProperty(name, c1Values[name.ordinal()]);
        C2Impl c2 = new C2Impl();
        Object[] c2Values = new Object[] { 5, 6., "baz" };
        for (P.Names name : P.Names.values())
            c2.setParentProperty(name, parentValues[name.ordinal()]);
        for (C2.Names name : C2.Names.values())
            c2.setChildProperty(name, c2Values[name.ordinal()]);
        C1 immutableC1 = new C1Immutable(c1);
        System.out.println("child 1: "+immutableC1);
        C2 immutableC2 = new C2Immutable(c2);
        System.out.println("child 2: "+immutableC2);
    }
}
class Parent
{
    private final long parentProperty;

    public long getParentProperty()
    {
        return parentProperty;
    }

    public static abstract class Builder<T extends Parent>
    {
        private long parentProperty;

        public Builder<T> withParentProperty( long parentProperty )
        {
            this.parentProperty = parentProperty;
            return this;
        }

        public abstract T build();
    }

    public static Builder<?> builder()
    {
        return new Builder<Parent>()
        {
            @Override
            public Parent build()
            {
                return new Parent(this);
            }
        };
    }

    protected Parent( Builder<?> builder )
    {
        this.parentProperty = builder.parentProperty;
    }
}

class Child1 extends Parent
{
    private final int child1Property;

    public int getChild1Property()
    {
        return child1Property;
    }

    public static abstract class Builder<T extends Child1> extends Parent.Builder<T>
    {
        private int child1Property;

        public Builder<T> withChild1Property( int child1Property )
        {
            this.child1Property = child1Property;
            return this;
        }

        public abstract T build();
    }

    public static Builder<?> builder()
    {
        return new Builder<Child1>()
        {
            @Override
            public Child1 build()
            {
                return new Child1(this);
            }
        };
    }

    protected Child1( Builder<?> builder )
    {
        super(builder);
        this.child1Property = builder.child1Property;
    }

}

class Child2 extends Parent
{

    private final String child2PropertyA;
    private final Object child2PropertyB;

    public String getChild2PropertyA()
    {
        return child2PropertyA;
    }

    public Object getChild2PropertyB()
    {
        return child2PropertyB;
    }

    public static abstract class Builder<T extends Child2> extends Parent.Builder<T>
    {
        private String child2PropertyA;
        private Object child2PropertyB;

        public Builder<T> withChild2PropertyA( String child2PropertyA )
        {
            this.child2PropertyA = child2PropertyA;
            return this;
        }

        public Builder<T> withChild2PropertyB( Object child2PropertyB )
        {
            this.child2PropertyB = child2PropertyB;
            return this;
        }
    }

    public static Builder<?> builder()
    {
        return new Builder<Child2>()
        {
            @Override
            public Child2 build()
            {
                return new Child2(this);
            }
        };
    }

    protected Child2( Builder<?> builder )
    {
        super(builder);
        this.child2PropertyA = builder.child2PropertyA;
        this.child2PropertyB = builder.child2PropertyB;
    }
}

class BuilderTest
{
    public static void main( String[] args )
    {
        Child1 child1 = Child1.builder()
                .withChild1Property(-3)
                .withParentProperty(5L)
                .build();

        Child2 grandchild = Child2.builder()
                .withChild2PropertyA("hello")
                .withChild2PropertyB(new Object())
                .withParentProperty(10L)
                .build();
    }
}