anony
anony

Reputation: 81

java enums in abstract class

I know about enums in java and how they are not inheritable and are final and all that. I've been looking for this and I still haven't been able to find the alternative to what I'd like to achieve. here's the general code, as simplifed as possible:

Class Utility

public abstract class Utility {

    public Utility() {
    }

    public abstract void run() throws Exception;
}

Class MyUtility1

public class MyUtility1 extends Utility {

    public MyUtility1() {
    }

    @Override
    public void run() throws Exception {
        //do something
    }
}

Class MyUtility2

public class MyUtility2 extends Utility {

    public MyUtility2() {
    }

    @Override
    public void run() throws Exception {
        //do something
    }
}

Class Main

public class Main {

    public static void main(String args[]) {
        try {
            Utility ut = null;
            if(/* something here */) {
                ut = new MyUtility1();
            } else {
                ut = new MyUtility2();
            }
            ut.run();
        } catch(MissingPropertyException e) {}
    }
}

Now what I need is to have a different set of constants on both MyUtility1 and MyUtility2. I'd use an enum for this:

Class MyUtility1

public class MyUtility1 extends Utility {

    public enum Properties {
        MONDAY("Monday"),
        TUESDAY("Tuesday");

        String property;

        Properties(String prop) {
            property = prop;
        }
    }

    public MyUtility1() {
    }

    @Override
    public void run() throws Exception {
        //do something
    }
}

Class MyUtility2

public class MyUtility2 extends Utility {

    public enum Properties {
        JANUARY("January"),
        FEBRUARY("February");

        String property;

        Properties(String prop) {
            property = prop;
        }
    }

    public MyUtility2() {
    }

    @Override
    public void run() throws Exception {
        //do something
    }
}

So far, everything is ok. What I miss now is a common method, preferably in Utility class, to do some validation of sort, regardless which enum is called. something like:

protected boolean checkProperties(Properties props) throws MissingPropertyException {
    for(Property property : props.values()) {
        /* do something */
    }
}

and on the super construtor call it like:

public Utility() throws MissingPropertyException {
    checkProperties(/* here comes the child.Properties */);
}

(yes I know the above would not compile, this is merely symbolic)

Any suggestions? If possible, leave an 'helper class' solution as last resort

Upvotes: 1

Views: 894

Answers (4)

niceman
niceman

Reputation: 2673

One suggestion is to make class Utility generic like this :

public abstract class Utility<T extends Enum<?>> {

     T[] properties
     public Utility() {
         checkProperties();
     }
     protected void checkProperties() throws MissingPropertyException;
     public abstract void run() throws Exception;
}

then define MyUtility1 like this :

class MyUtility1 extends Utility<MyProperties1> { //class body }  

And so on for MyUtility2, note that on main , variable ut should be declared Utility<?> .
This solution has shortcomings, for example if you have a function in Utility that takes T as paramater and you want it to be polymorphic it wouldn't work.

Another suggestion is to make properties Enum<?>[] instead of T[], Enum is an abstract class so there are some problems with this, first you need to cast whenever you want to deal with the real type, like in checkProperties for example.

Second any enum can be put in properties so you have to make some function addProperty and this function must validate the type of the property passed in.

I think the best solution is to leave enums out of inheritance :) .

Upvotes: 0

Jaiprakash
Jaiprakash

Reputation: 609

Convert checkProperties to abstract to be implemented by the classes.

 protected abstract boolean checkProperties() throws MissingPropertyException;

Now implement the checkProperties in both the classes, as per requirement. If the same method is used to check, create it in utility class.

Alternatively change

   protected boolean checkProperties(Class<? extends Enum> clazz) throws MissingPropertyException {
           Enum[] enum =  clazz.getEnumConstants(); //Do required validation here
}

and in the constructor call appropriate Properties.class

public MyUtility2() {
   super(Properties.class)    
}


public Utility(Class<? extends Enum> clazz) throws MissingPropertyException {
    checkProperties(clazz);
}

as for(Property property : props.values()) { //Cannot work for any property.

Upvotes: 0

Ji aSH
Ji aSH

Reputation: 3457

To me it sounds like you want to use generics.

Lets image that you extract your properties to 'Day' and 'Month' enum, your Utility1 and Utility2 class seems to be kind of 'Utility' and 'Utility'

To complete your samples this would be something like :

Utility.java

public abstract class Utility<T> {
    protected Utility(T prop) throws Exception {
        checkProperties(prop);
    }
    public abstract void run() throws Exception;
    public abstract void checkProperties(T prop) throws Exception;
}

Utility1.java

public class Utility1 extends Utility<Day> {
    public Utility1(Day day) throws Exception {
        super(day);
    }
    @Override
    public void run() throws Exception { }
    @Override
    public void checkProperties(Day prop) throws Exception { }
}

Utility2.java

public class Utility2 extends Utility<Month> {
    public Utility2(Month month) throws Exception {
        super(month);
    }
    @Override
    public void run() throws Exception { }
    @Override
    public void checkProperties(Month prop) throws Exception { }
}

Day.java

public enum Day {
    MONDAY, TUESDAY;
}

Month.java

public enum Month implements IProperties {
    JANUARY, FEBRUARY;
}

You could additionnaly have your enums implement an interface (say IProperties) and make Utility to enforce stronger typing

Upvotes: 0

duffymo
duffymo

Reputation: 308763

Looks like you want to embed scheduling rules inside your Utility instances. I think that's a bad idea.

A better idea would be to have all your Utility classes implement Runnable or Callable. Give those to scheduled Executor instances that would carry the rules.

Separate what's done from when it's done. You might want to change the schedule without having to modify the Utility instances. Externalizing that logic and making it configurable will make it easy.

Upvotes: 1

Related Questions