Question

Lately I had been trying to make an relativistic energy calculator. I used List<ComponentType> to represent any particle build on ComponentType.ELECTRON, ComponentType.PROTON and ComponentType.NEUTRON, where ComponentType is a enum containing mass.

Later I wanted to make an ParticleFactory Class which would correspond to a list of basic particles in GUI drop down list. Like: ParticleFactory(Hydrogen) would give me an Particle object containing {ComponentType.ELECTRON, ComponentType.PROTON} list. This would make the modification easy because ParticleFactory and GUI would use the same enum with basic particles.

Problem arisen when I tried to implement it. I know that it has no chance of working with improper syntax but no matter what I do I always get errors.

public enum GenericParticleType {

ELECTRON({"electron","e"}, new ArrayList<ComponentType>());

private final String[] names;
private final List<ComponentType> components;

GenericParticleType(String[] names, List<ComponentType> components) {
    this.names = names;
    this.components = components;
    }   
}

The goal is to make enum contain list of other enums. :D Is there any proper way of doing this?

Is there perhaps a better way of doing this? A constant HashMap?

Était-ce utile?

La solution

I think you are wanting the following design:

  • An interface called GenericParticle.
  • Enums that give the most basic implementations.
  • A factory/builder where you can make whatever you want.

You can achieve this with the following code:

enum Component {
    ELECTRON, PROTON, NEUTRON;
}

interface GenericParticle {
    List<String> getNames();

    List<Component> getComponents();
}

enum BasicGenericParticle implements GenericParticle {
    ELECTRON(
            Arrays.asList("electron", "e"),
            Arrays.asList(Component.ELECTRON)
    ),
    HYDROGEN(
            Arrays.asList("hydrogen", "h"),
            Arrays.asList(Component.ELECTRON, Component.PROTON)
    )
    ;

    private final List<String> names;
    private final List<Component> components;

    private BasicGenericParticle(final List<String> names, final List<Component> components) {
        this.names = names;
        this.components = components;
    }

    @Override
    public List<String> getNames() {
        return new ArrayList<>(names);
    }

    @Override
    public List<Component> getComponents() {
        return new ArrayList<>(components);
    }
}

class GenericParticleBuilder {
    private List<String> names = new ArrayList<>();
    private List<Component> components = new ArrayList<>();

    public GenericParticleBuilder name(final String name) {
        names.add(name);
        return this;
    }

    public GenericParticleBuilder component(final Component component) {
        components.add(component);
        return this;
    }

    public GenericParticle build() {
        return new GenericParticleImpl(names, components);
    }

    private static class GenericParticleImpl implements GenericParticle {
        private List<String> names = new ArrayList<>();
        private List<Component> components = new ArrayList<>();

        public GenericParticleImpl(final List<String> names, final List<Component> components) {
            this.names = names;
            this.components = components;
        }

        @Override
        public List<String> getNames() {
            return new ArrayList<>(names);
        }

        @Override
        public List<Component> getComponents() {
            return new ArrayList<>(components);
        }
    }
}

Used as:

    GenericParticle electron = BasicGenericParticle.ELECTRON;
    GenericParticle hydrogen = BasicGenericParticle.HYDROGEN;
    GenericParticle water = new GenericParticleBuilder()
            .name("water").name("h2o2")
            .component(/*components*/)
            .build();

You do need to take precautions on your set for the following facts:

  • No illegal particles should be constructable, unless of course a client implements GenericParticle on his own, but for that you have documentation to ensure he does the correct things.
  • The performance of defensive copying is not the best, but you absolutely want the strings to be immutable. You could consider either implementing an immutable list yourself (it should not be possible to change the elements in the list), or use one provided by a library such as guava (preferable). I wouldn't use a String array as they put a lot of burden on other developers and yourself, I would prefer objects.

Autres conseils

I see no problem in this:

public enum GenericParticleType {

    ELECTRON(new String[] { "electron", "e" },
            new ArrayList<GenericParticleType>()),

    MULTI_ELECTRON(new String[] { "me" }, Arrays.asList(ELECTRON, ELECTRON)),

    COMPOSITION(new String[] { "c" }, Arrays.asList(MULTI_ELECTRON, ELECTRON,
            ELECTRON));

    private final String[] names;

    private final List<GenericParticleType> components;

    GenericParticleType(String[] names, List<GenericParticleType> components) {
        this.names = names;
        this.components = components;
    }

    public String[] getNames() {
        return names;
    }

    public List<GenericParticleType> getComponents() {
        return components;
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top