Reputation: 81
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
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
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
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
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