1

If I have a standard enum (in this example a representation of a list of buildings) such as this:

public enum BuildingType {
   farm, shop, house
}

and a function that creates objects based on a "building" superclass such as:

public void addBuilding(BuildingType bType) {
   Building b = new Building();
   b.start();
}

All of my subclasses have names matching the BuildingType enum. Is there a way that I can use my enum parameter to set the class of object b without a class statement?

clearly incorrectly, but something like this

Building b = new bType(); //using the argument

Thanks as always.

5 Answers 5

2

You can define an enum that is also a factory:

public enum BuildingType {
    farm(Farm.class),
    shop(Shop.class),
    house(House.class);
    private Class<? extends Building> clazz;
    private BuildingType(Class<? extends Building> clazz) {
        this.clazz = clazz;
    }

    public Building createBuilding() {
        try {
            return clazz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(clazz + " has no default constructor");
        }
    }
}

Or slightly more code, but avoiding reflection, make the enum class an abstract factory and let the instances be factories:

public enum BuildingType {
    farm() {
        public Building createBuilding() {
            return new Farm();
        }
    },
    shop() {
        public Building createBuilding() {
            return new Shop();
        }
    },
    house() {
        public Building createBuilding() {
            return new House();
        }
    };

    public abstract Building createBuilding();
}

Either way, to use:

public void addBuilding(BuildingType bType) {
   Building b = bType.createBuilding();
   b.start();
}
Sign up to request clarification or add additional context in comments.

5 Comments

Is there any reason using reflection? The enums could simply instantiate the buildings with constructor, right?
@katona you couldn't do it in the constructor, because then you would return the same Building instance every time, but you could do it with an abstract factory pattern on the enum and have the enums themselves be the factories. See updated answer.
Great answer. Is there a reason to avoid reflection? i don't have any experience with it.
@TrewTzu reflection is in general "less safe", because the compiler can't check most operations. In this example, the call to newInstance() assumes a default constructor exists. If one doesn't (which may become the case in the future), an exception is thrown at runtime, whereas in the non-reflection version, problems are detected at compile time (much easier to detect and fix). Further, construction can be tailored for each type, eg return new House(3); eg for 3 bedrooms or whatever, or even be locale based, or even delegate to an injected factory.
Happy to see the update, that is exactly what I meant in my previous comment. Using constructor makes it less readable though... Great answer anyway!
0

It would be a more OO appropriate way, if the different behaviour of buildings would be represented in a class hierarchy rather than enum literals - i.e., having a FarmBuilding, a ShopBuilding and a HouseBuilding sub class of a Building abstract base class implementing the Building specific behaviour.

Comments

0

You could create a parameter that declares what class type each enum is referencing to. It could look like this:

// Enums should be all caps btw
public enum BuildingType {
   FARM(Farm.class), SHOP(Shop.class), HOUSE(House.class);
   private Class<? extends Building> type;
   private BuildingType(Class<? extends Building> type) {
       this.type = type;
   }

   public Class<? extends Building> getType() {
       return type;
   }
}

you could then create a new instance of that class when you need.

Building myBuilding = BuildingType.FARM.getType().newInstance();

This sample assumes you have a default no arguments constructor for your class as well so watch out for that.

2 Comments

What about unifying this with the abstract factory design pattern, i.e. let the enums create the buildings?
@Katona I think this style of class in enum for any factory style design pattern isnt ideal. Fixing your creatable types inside an enum is a shutdown switch for any further hierarchy someone else may want to put on top. If your in a set enviroment like a game its whatever but if your building a framework of some kind I dont think it would be a good idea. Especially because its really not necessary.
0

I recommend you to read about design patterns and especially about Factory pattern. Here is a wiki link http://en.wikipedia.org/wiki/Software_design_pattern , but you can find a ton of examples in the internet. For example

BuildingFactory bf = BuildingFactory.newInstance();
Building b = bf.createBuilding(bType);

and in createBuilding method:

// return Building superclass which you can cast to specific type

public Building createBuilding(BuildingType bType) {
 if(bType == something) {
    return new FarmBuilding();
 }
 else if(...) {
    return something else;
 }
}

1 Comment

There is no design pattern Factory. There's Factory Method, Abstract Factory, no just Factory...
0

Like some answers above state, you could use an abstract method to implement them on the Enums. Unlike many say, you CAN use reflection to instantiate an Object with parameters, like this:

public enum BuildingType {
    FARM(Farm.class), SHOP(Shop.class), HOUSE(House.class);

    private final Class<? extends Building> buildingType;

    private BuildingType(Class<? extends Building> buildingType ) {
        this.buildingType = buildingType;
    }

    public Building getBuilding( Furniture... furniture ) {
        Building building = null;
        try {
            Constructor<? extends Building> constructor = 
                    ( Constructor<? extends Building> ) buildingType.getDeclaredConstructor( Furniture[].class );
            building = constructor.newInstance( furniture );
        }
        catch ( NoSuchMethodException | SecurityException | 
                InstantiationException | IllegalAccessException | 
                IllegalArgumentException | InvocationTargetException ex ) {
            //I have a method to handle exceptions, you could do the same, 
            //but in principle it shouldn't be necessary.
            //handleExceptionsGracefully(...);
        }

        return building;
    }
}

For more on reflection, I advise you to read this from O'reilly: http://chimera.labs.oreilly.com/books/1234000001805/ch07.html#learnjava3-CHP-7-SECT-2

And to Bohemian: for convention, Java Enums should be Upercase, and if you don't have arguments in Enums, you can remove the parentheses.

I hope I have helped.

Have a nice day. :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.