I have a number of enums that each have the same fields and the same methods.
public enum AddressSubType {
DOM("dom"), INTL("intl"), POSTAL("postal");
private final String keyword;
private AddressSubType(String keyword) {
this.keyword = keyword;
}
public String getKeyword() {
return keyword;
}
@Override
public String toString() {
return keyword;
}
}
public enum EmailSubType {
INTERNET("internet"), X400("x.400");
private final String keyword;
private EmailSubType(String keyword) {
this.keyword = keyword;
}
public String getKeyword() {
return keyword;
}
@Override
public String toString() {
return keyword;
}
}
Is there a way for these enums to share the fields and methods (like a parent class)? I know that it's not possible to extend enums. Thanks.
I will be the one to say it. This is an awful idea.
The enum does not care about anything else except the hard coded values inside. Typically when one decides to group things in an Object Oriented way, they make sure that all of the objects are related. By virtue of being an enum these files are no more related than two classes that are subtypes of Object. If you are looking to have shared functionality between all enums in your domain you will want to look at some static functions, or a utility class as it is often referred to (this has its own series of issues at the end of the day). Essentially the class will have a series of functions that encapsulate all the shared logic, the signature will generally look like so:
There's not much you can do in this case, and even in a more complex example, the best place to put common code might be in a utility class that all the enums could use, or in a separate class that would be included in the enums via composition (each enum would have an instance of that class, perhaps called Keyword).
If the code for the
toString
method were complex and you didn't want to restate it in each enum, or move it to a contained object, Java 8 has a mechanism that you could use. It is overkill in this example. You could define an interface that your enums would all use. The state (keyword) must still live in your enums, since interfaces cannot have state, but starting with Java 8 you can provide default implementations of methods:Your enums would implement this interface:
Notice the strange new syntax in the
toString
methods. The rule for default methods in interfaces is that method resolution always prefers class methods over interfaces. So even though we provide a default implementation oftoString
inCommon
, the one in the enum will take precedence, and the one inObject
would if there wasn't one in the enum. So if you want to use a default method from an interface that supersedes one of the methods fromObject
(liketoString
, orhashCode
, orequals
), then you have to call it explicitly with this newinterface.super.method()
syntax.We don't have to jump through any extra hoops for the
toDescriptiveString
method, though. That one is brand new ininterface Common
, and it isn't provided by our enums, so they get the default implementation provided by the interface. (If they wanted to override it with their own method, they could, just like any other inherited method.)We can use the default methods like any other methods of an object, of course:
Which prints out:
In this case, however, if it wasn't for the rather verbose
toDescriptiveString
method, the enum classes wouldn't be a bit shorter withinterface Common
than they would be without. Default methods in interfaces will really shine when it comes to adding new functionality to existing interfaces, something not possible without breaking all implementers of an interface in previous versions of Java.All of this is based on the as-yet-incomplete Java SE 8 with Lambda. You can download a pre-release build, but be aware that it is a work in progress.
I would probably combine them into a single enum object where some are initialized with an "Postal" flag set to true and some have the "email" flag set to true since the two are really just different "types" of addresses.
You can then have it return iterators for either if you wish to access them separately or you can iterate over the whole thing.
You may also find some of the rest of your code becoming simplified, for instance just having a collection of "Address"es and checking at runtime to see if a given address is email or postal.
But it depends on how similar they really are.
You can declare an
interface
that they both can implement. This would allow you to pass either enum type as an argument to a method that only cares about specific methods on that inerface. However, this will only allow you to "share" the method signatures, not the fields or the method implementations.If your enums are as trivial as in the given example, you don't have any significant amount of code repetition, so this probably isn't a problem. If you find that your methods have more complex, repetitive code, you should consider delegating that responsibility to a separate class.
If you really want to model an inheritance pattern (e.g.
EmailAddress
"is a"Address
), then you'll need to get away fromenums
. You could just use some static fields to simulate the enum pattern, but have each of them be an instance of a specific class.You could create a Value class
Then you can create Classes with public static final values like this :