Builder pattern for polymorphic object hierarchy: possible with Java?

后端 未结 6 884
谎友^
谎友^ 2020-12-08 01:11

I have a hierarchy of interfaces, with Child implementing Parent. I would like to work with immutable objects, so I would like to design Bui

6条回答
  •  刺人心
    刺人心 (楼主)
    2020-12-08 01:46

    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 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 parentNameToValue = new EnumMap(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 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 nameToValue = new EnumMap(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 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 nameToValue = new EnumMap(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);
        }
    }
    

提交回复
热议问题