I have an enum from a common Library (it cannot be changed) as a field from a Class.
I need to use that enum values as a switch-case in order to do something accordingly (for example save some data to a database).
This is for a Java 11 micro-service using Spring as a framework.
What I did before knowing the enum has to stay immutable, I avoided an ugly switch case with an overridden abstract function inside the enum like this:
public enum InvoiceStatus {
DRAFT {
#Override public void action(InputMessage inputMessage) {
invoiceFileService.draft(inputMessage);
}
},
VALID {
#Override public void action(InputMessage inputMessage) {
invoiceFileService.valid(eiInvoiceFileMessage);
}
},
NOT_VALID {
#Override public void action(InputMessage inputMessage) {
invoiceFileService.notValid(eiInvoiceFileMessage);
}
};
//+20 more values...
#Autowired
InvoiceFileService invoiceFileService;
public abstract void action(InputMessage inputMessage);
}
and I simply called the enum like this, so with different values from the enum the called function from the service would be different without writing a long switch-case.
invoice.getStatus().action(inputMessage);
Now the new requirement needs the enum to live inside a common library so it can refer to InvoiceFileService class which will be only local to my project.
I tried different options like HashMaps but the code went ugly and un-maintainable.
Is there a clean way to extend the simple enum (with only values definition) and add to it the abstract function to do stuff? maybe java 8 added some new way to do this.
You could create a wrapper enum.
public enum WrappedInvoiceStatus {
DRAFT(InvoiceStatus.DRAFT, this::someAction),
// other values
private WrappedInvoiceStatus(InvoiceStatus status, Action action) {
this.status = status;
this.action = action;
}
private interface Action { // can be one of Java default functional interfaces as well
void doSomething(InputMessage msg);
}
private void someAction(InputMessage msg) {
// behavior
}
// some plumbing required
}
Basically I’m suggesting using wrapping and lambda expressions or method references. The world of functional programming takes some getting used to. Not everyone is a fan. Your mileage may vary.
As others already said, you can not extend the enum at runtime.
But an enum can implement an interface.
So the basic idea is:
You make an interface with the action as sole abstract method:
public interface InvoiceAction {
void action(InputMessage message);
}
Your enum implements that interface
public enum InvoiceStatus implements InvoiceAction {
// ... no other changes needed
}
In all the cases where you only need to use the actual action, change InvoiceStatus to InvoiceAction. This is the most risky change. Make sure to recompile all code.
Because InvoiceAction only has one abstract method, it's a functional interface, and can be implemented with a lambda expression:
invoice.setStatus(msg -> ...);
This change is probably the most invasive change, but it might be the right thing to do - if you need a different action next time, you won't have the same problem as today.
Enum type is not extendable and implicitly final as specified in JLS:-
An enum declaration is implicitly final unless it contains at least one enum constant that has a class body (§8.9.1).
Hence a class could not extends an enum type. However you could use wrapper or adapter pattern to add additional behaviours/fields of the enum. For example:-
#Service
public class SimpleInvoiceFileService implements InvoiceFileService{
private final InvoiceStatus invoiceStatus;
public SimpleInvoiceFileService(InvoiceStatus status){
invoiceStatus = status;
}
#Override
public void draft(InputMessage input){
this.invoiceStatus.action(input);
}
#Override
public void valid(InputMessage input){
this.invoiceStatus.action(input);
}
// Add more methods to InvoiceFileService interface
// as required and override them here.
}
JLS Reference:-
https://docs.oracle.com/javase/specs/jls/se11/html/jls-8.html#jls-8.9
Related
Sealed classes and sealed interfaces were a preview feature in Java 15, with a second preview in Java 16, and now proposed delivery in Java 17.
They have provided classic examples like Shape -> Circle, Rectangle, etc.
I understand sealed classes: the switch statement example provided makes sense to me. But, sealed interfaces are a mystery to me. Any class implementing an interface is forced to provide definitions for them. Interfaces don't compromise the integrity of the implementation because the interface is stateless on its own. Doesn't matter whether I wanted to limit implementation to a few selected classes.
Could you tell me the proper use case of sealed interfaces in Java 15+?
Basically to give a sealed hierarchy when there is no concrete state to share across the different members. That's the major difference between implementing an interface and extending a class - interfaces don't have fields or constructors of their own.
But in a way, that isn't the important question. The real issue is why you would want a sealed hierarchy to begin with. Once that is established it should be clearer where sealed interfaces fit in.
(apologies in advance for the contrived-ness of examples and the long winded-ness)
1. To use subclassing without "designing for subclassing".
Lets say you have a class like this, and it is in a library you already published.
public final class Airport {
private List<String> peopleBooked;
public Airport() {
this.peopleBooked = new ArrayList<>();
}
public void bookPerson(String name) {
this.peopleBooked.add(name);
}
public void bookPeople(String... names) {
for (String name : names) {
this.bookPerson(name);
}
}
public int peopleBooked() {
return this.peopleBooked.size();
}
}
Now, you want to add a new version to your library that will print out the names of people booked as they are booked. There are several possible paths to do this.
If you were designing from scratch, you could reasonably replace the Airport class with an Airport interface and design the PrintingAirport to compose with a BasicAirport like so.
public interface Airport {
void bookPerson(String name);
void bookPeople(String... names);
int peopleBooked();
}
public final class BasicAirport implements Airport {
private final List<String> peopleBooked;
public Airport() {
this.peopleBooked = new ArrayList<>();
}
#Override
public void bookPerson(String name) {
this.peopleBooked.add(name);
}
#Override
public void bookPeople(String... names) {
for (String name : names) {
this.bookPerson(name);
}
}
#Override
public int peopleBooked() {
return this.peopleBooked.size();
}
}
public final class PrintingAirport implements Airport {
private final Airport delegateTo;
public PrintingAirport(Airport delegateTo) {
this.delegateTo = delegateTo;
}
#Override
public void bookPerson(String name) {
System.out.println(name);
this.delegateTo.bookPerson(name);
}
#Override
public void bookPeople(String... names) {
for (String name : names) {
System.out.println(name);
}
this.delegateTo.bookPeople(names);
}
#Override
public int peopleBooked() {
return this.peopleBooked.size();
}
}
This isn't doable in our hypothetical though because the Airport class already exists. There are going to be calls to new Airport() and methods that expect something of type Airport specifically that can't be kept in a backwards compatible way unless we use inheritance.
So to do that pre-java 15 you would remove the final from your class and write the subclass.
public class Airport {
private List<String> peopleBooked;
public Airport() {
this.peopleBooked = new ArrayList<>();
}
public void bookPerson(String name) {
this.peopleBooked.add(name);
}
public void bookPeople(String... names) {
for (String name : names) {
this.bookPerson(name);
}
}
public int peopleBooked() {
return this.peopleBooked.size();
}
}
public final class PrintingAirport extends Airport {
#Override
public void bookPerson(String name) {
System.out.println(name);
super.bookPerson(name);
}
}
At which point we run into one of the most basic issues with inheritance - there are tons of ways to "break encapsulation". Because the bookPeople method in Airport happens to call this.bookPerson internally, our PrintingAirport class works as designed, because its new bookPerson method will end up being called once for every person.
But if the Airport class were changed to this,
public class Airport {
private List<String> peopleBooked;
public Airport() {
this.peopleBooked = new ArrayList<>();
}
public void bookPerson(String name) {
this.peopleBooked.add(name);
}
public void bookPeople(String... names) {
for (String name : names) {
this.peopleBooked.add(name);
}
}
public int peopleBooked() {
return this.peopleBooked.size();
}
}
then the PrintingAirport subclass won't behave correctly unless it also overrided bookPeople. Make the reverse change and it won't behave correctly unless it didn't override bookPeople.
This isn't the end of the world or anything, its just something that needs to be considered and documented - "how do you extend this class and what are you allowed to override", but when you have a public class open to extension anyone can extend it.
If you skip documenting how to subclass or don't document enough its easy to end up in a situation where code you don't control that uses your library or module can depend on a small detail of a superclass that you are now stuck with.
Sealed classes let you side step this by opening your superclass up to extension only for the classes you want to.
public sealed class Airport permits PrintingAirport {
// ...
}
And now you don't need to document anything to outside consumers, just yourself.
So how do interfaces fit in to this? Well, lets say you did think ahead and you have the system where you are adding features via composition.
public interface Airport {
// ...
}
public final class BasicAirport implements Airport {
// ...
}
public final class PrintingAirport implements Airport {
// ...
}
You might not be sure that you don't want to use inheritance later to save some duplication between the classes, but because your Airport interface is public you would need to make some intermediate abstract class or something similar.
You can be defensive and say "you know what, until I have a better idea of where I want this API to go I am going to be the only one able to make implementations of the interface".
public sealed interface Airport permits BasicAirport, PrintingAirport {
// ...
}
public final class BasicAirport implements Airport {
// ...
}
public final class PrintingAirport implements Airport {
// ...
}
2. To represent data "cases" that have different shapes.
Lets say you send a request to a web service and it is going to return one of two things in JSON.
{
"color": "red",
"scaryness": 10,
"boldness": 5
}
{
"color": "blue",
"favorite_god": "Poseidon"
}
Somewhat contrived, sure, but you can easily imagine a "type" field or similar that distinguishes what other fields will be present.
Because this is Java, we are going to want to map the raw untyped JSON representation into classes. Lets play out this situation.
One way is to have one class that contains all the possible fields and just have some be null depending.
public enum SillyColor {
RED, BLUE
}
public final class SillyResponse {
private final SillyColor color;
private final Integer scaryness;
private final Integer boldness;
private final String favoriteGod;
private SillyResponse(
SillyColor color,
Integer scaryness,
Integer boldness,
String favoriteGod
) {
this.color = color;
this.scaryness = scaryness;
this.boldness = boldness;
this.favoriteGod = favoriteGod;
}
public static SillyResponse red(int scaryness, int boldness) {
return new SillyResponse(SillyColor.RED, scaryness, boldness, null);
}
public static SillyResponse blue(String favoriteGod) {
return new SillyResponse(SillyColor.BLUE, null, null, favoriteGod);
}
// accessors, toString, equals, hashCode
}
While this technically works in that it does contain all the data, there isn't all that much gained in terms of type-level safety. Any code that gets a SillyResponse needs to know to check the color itself before accessing any other properties of the object and it needs to know which ones are safe to get.
We can at least make the color an enum instead of a string so that code shouldn't need to handle any other colors, but its still far less than ideal. It gets even worse the more complicated or more numerous the different cases become.
What we ideally want to do is have some common supertype to all the cases that you can switch on.
Because its no longer going to be needed to switch on, the color property won't be strictly necessary but depending on personal taste you can keep that as something accessible on the interface.
public interface SillyResponse {
SillyColor color();
}
Now the two subclasses will have different sets of methods, and code that gets either one can use instanceof to figure out which they have.
public final class Red implements SillyResponse {
private final int scaryness;
private final int boldness;
#Override
public SillyColor color() {
return SillyColor.RED;
}
// constructor, accessors, toString, equals, hashCode
}
public final class Blue implements SillyResponse {
private final String favoriteGod;
#Override
public SillyColor color() {
return SillyColor.BLUE;
}
// constructor, accessors, toString, equals, hashCode
}
The issue is that, because SillyResponse is a public interface, anyone can implement it and Red and Blue aren't necessarily the only subclasses that can exist.
if (resp instanceof Red) {
// ... access things only on red ...
}
else if (resp instanceof Blue) {
// ... access things only on blue ...
}
else {
throw new RuntimeException("oh no");
}
Which means this "oh no" case can always happen.
An aside: Before java 15 to remedy this people used the "type safe visitor" pattern. I recommend not learning that for your sanity, but if you are curious you can look at code ANTLR generates - its all a large hierarchy of differently "shaped" data structures.
Sealed classes let you say "hey, these are the only cases that matter."
public sealed interface SillyResponse permits Red, Blue {
SillyColor color();
}
And even if the cases share zero methods, the interface can function just as well as a "marker type", and still give you a type to write when you expect one of the cases.
public sealed interface SillyResponse permits Red, Blue {
}
At which point you might start to see the resemblance to enums.
public enum Color { Red, Blue }
enums say "these two instances are the only two possibilities." They can have some methods and fields to them.
public enum Color {
Red("red"),
Blue("blue");
private final String name;
private Color(String name) {
this.name = name;
}
public String name() {
return this.name;
}
}
But all instances need to have the same methods and the same fields and those values need to be constants. In a sealed hierarchy you get the same "these are the only two cases" guarantee, but the different cases can have non-constant data and different data from each other - if that makes sense.
The whole pattern of "sealed interface + 2 or more record classes" is fairly close to what is intended by constructs like rust's enums.
This also applies equally to general objects that have different "shapes" of behaviors, but they don't get their own bullet point.
3. To force an invariant
There are some invariants, like immutability, that are impossible to guarantee if you allow subclasses.
// All apples should be immutable!
public interface Apple {
String color();
}
public class GrannySmith implements Apple {
public String color; // granny, no!
public String color() {
return this.color;
}
}
And those invariants might be relied upon later on in the code, like when giving an object to another thread or similar. Making the hierarchy sealed means you can document and guarantee stronger invariants than if you allowed arbitrary subclassing.
To cap off
Sealed interfaces more or less serve the same purpose as sealed classes, you just only use concrete inheritance when you want to share implementation between classes that goes beyond what something like default methods can give.
Although interfaces have no state themselves, they have access to state, eg via getters, and may have code that does something with that state via default methods.
Therefore the reasoning supporting sealed for classes may also be applied to interfaces.
Suppose you write an authentication library, containing an interface for password encoding, ie char[] encryptPassword(char[] pw). Your library provides a couple of implementations the user can choose from.
You don't want him to be able to pass in his own implementation that might be insecure.
Could you tell me the proper use case of sealed interfaces in Java
15+?
I wrote some experimental code and a supporting blog to illustrate how sealed interfaces could be used to implement an ImmutableCollection interface hierarchy for Java that provides contractual, structural and verifiable immutability. I think this could be a practical use case for sealed interfaces.
The example includes four sealed interfaces: ImmutableCollection, ImmutableSet, ImmutableList and ImmutableBag. ImmutableCollection is extended by ImmutableList/Set/Bag. Each of the leaf interfaces permits two final concrete implementations. This blog describes the design goal of restricting the interfaces so developers cannot implement "Immutable" interfaces and provide implementations that are mutable.
Note: I am a committer for Eclipse Collections.
Interfaces are not always entirely defined by their API alone. Take, for example ProtocolFamily. This interface would be easy to implement, considering its methods, but the result would not be useful regarding the intended semantics, as all methods accepting ProtocolFamily as input would just throw UnsupportedOperationException, in the best case.
This is a typical example for an interface that would be sealed if that feature existed in earlier versions; the interface is intended to abstract the implementations exported by a library, but not to have implementations outside that library.
The newer type ConstantDesc mentions that intention even explicitly:
Non-platform classes should not implement ConstantDesc directly. Instead, they should extend DynamicConstantDesc…
API Note:
In the future, if the Java language permits, ConstantDesc may become a sealed interface, which would prohibit subclassing except by explicitly permitted types.
Regarding possible use cases, there is no difference between a sealed abstract class and a sealed interface, but the sealed interface still allows implementors extending different classes (within the limits set by the author). Or being implemented by enum types.
In short, sometimes, interfaces are used to have the least coupling between a library and its clients, without the intention of having client-side implementations of it.
Since Java introduced records in version 14, one use case for sealed interfaces will certainly be to create sealed records. This is not possible with sealed classes, because records cannot extend a class (much like enums).
Before java 15 developers used to think in a way that code reusability is the goal. But it's not true to all extents, in some cases we want wide accessibility but not extensibility for better security and also codebase management.
This feature is about enabling more fine-grained inheritance control in Java. Sealing allows classes and interfaces to define their permitted subtypes.
The sealed interface allows us to enable it to reason clearly all the classes that can implement it.
Having something like this:
public enum Token
{
FOO("foo", "f"),
QUIT("quit", "q"),
UNKNOWN("", "");
...
public parse(String s) {
for (Token token : values()) {
...
return token;
}
return UNKNOWN;
}
}
An abstract class:
abstract class Base
{
private boolean run;
Base() {
run = true;
while (run) {
inp = getInput();
act(inp);
}
}
public boolean act(String s) {
boolean OK = true;
switch (Token.parse(inp)) { /* Enum */
case FOO:
do_foo();
break;
case QUIT:
run = false;
break;
case UNKNOWN:
print "Unknown" + inp;
OK = false;
break;
}
}
return OK;
}
}
And the extender:
class Major extends Base
{
}
What I want is to extend act as in if super does not handle it then try to handle it in Major. E.g. add PRINT_STAT("print-statistics", "ps") - but at the same time let the Base class handle defaults like QUIT.
Is this a completely wrong approach?
What I have done so far is add an interface Typically:
public interface BaseFace
{
public boolean act_other(String inp);
}
And in class Base implements BaseFace:
case UNKNOWN:
OK = act_other(inp);
And in class Major:
public boolean act_other(String inp) {
if (inp.equals("blah")) {
do_blah();
return true;
}
return false;
}
Does this look like a usable design?
And, major question:
Is there some good way to extend the Token class such that I can use the same switch approach in Major as in Base? What I wonder is if there for one is a better design and second if I have to make a new Token class for Major or if I somehow can extend or otherwise re-use the existing.
Edit: Point of concept is to have the Base class that I can easily re-use in different projects handling various types of input.
All enums implicity extend Enum. In Java, a class can extend at most one other class.
You can, however, have your enum class implement an interface.
From this Java tutorial on Enum Types:
Note: All enums implicitly extend java.lang.Enum. Because a class can only extend one parent (see Declaring Classes), the Java language does not support multiple inheritance of state (see Multiple Inheritance of State, Implementation, and Type), and therefore an enum cannot extend anything else.
Edit for Java 8:
As of Java 8, an interface can include default methods. This allows you to include method implementations (but not state) in interfaces. Although the primary purpose of this capability is to allow evolution of public interfaces, you could use this to inherit a custom method defining a common behavior among multiple enum classes.
However, this could be brittle. If a method with the same signature were later added to the java.lang.Enum class, it would override your default methods . (When a method is defined both in a class's superclass and interfaces, the class implementation always wins.)
For example:
interface IFoo {
public default String name() {
return "foo";
}
}
enum MyEnum implements IFoo {
A, B, C
}
System.out.println( MyEnum.A.name() ); // Prints "A", not "foo" - superclass Enum wins
Your problem seems a good candidate for the Command Pattern
It is a good practice to use an enum as a logical group of supported actions. IMO, having a single enum to group all supported actions will improve the readability of your code. With this in mind, the Token enum should contain all the supported action types
enum Token
{
FOO("foo", "do_foo"),
QUIT("quit", "do_quit"),
PRINT_STATS("print", "do_print_stats"),
UNKNOWN("unknown", "unknown")
.....
}
Consider creating an interface Actor which defines an a method say act as shown below:
public interface Actor
{
public void act();
}
Instead of having a single Base class that does too may things, you can have one class per supported command for e.g.
public class FooActor implements Actor
{
public void act()
{
do_foo(); //call some method like do_foo
}
}
public class PrintActor implements Actor
{
public void act()
{
print_stats(); //call some print stats
}
}
Finally, there will be a driver code that will take in as input the action to be performed, initialize the appropriate Actor and execute the action by invoking the act() method.
public class Driver
{
public static void main(String[] args)
{
String command; // will hold the input string from the user.
//fetch input from the user and store it in command
Token token = Token.parse(command);
switch(token)
{
case FOO:
new FooActor().act();
break;
case PRINT_STATS:
new PrintActor().act();
break;
....
}
}
}
Such a design will ensure that you can easily add new commands and the code remains modular.
As other say here, You can't extend enum. From design perspective this solution looks like it's too tightly coupled. I would advise to use more dynamic approach for this. You can create some kind of behavior map:
Map<Token, Runnable> behaviors;
This map could be easily modified or replaced. You can even store some sets of those predefined behaviors. In example:
behaviors.get(Token.parse(inp)).run();
(some additional checks are needed here of course)
And last note: in most cases avoid inheritance
You need to factor out an interface. It is, after all, a fairly common practice to always start with an interface, then provide an abstract class to supply some default implementations. If you have an interface, you can make the enum implement the interface.
Good day!
I have an interface which only implements one single method. I dont feel like making several class which all implement this one single method therefore I decided to use anonymous classes instead.
I use enums for certain static items, these enums have instances of my interface. However, when I try to make an anonymous class inside my enum constants my IDE (eclipse) literally tells me nothing (as if it is outside a code block).
My question is as follows: Can I use anonymous classes inside my enum constants?
If my text was unclear (Sorry im not english) please see the example below.
Code example
/**
* My Interface
*/
public interface IPotato {
public void eatPotato();
}
/**
* My enum class
*/
public enum PotatoEnum {
I_WANT_TO_EAT_POTATO(new IPotato() {
#Override
public void eatPotato() {
// Cant put code here.
} });
private IPotato _myAnonymousClass;
private PotatoEnum(IPotato anonymousClass){
this._myAnonymousClass = anonymousClass;
}
public IPotato getPotato(){
return _myAnonymousClass;
}
}
You could do that, it is a perfectly valid solution.
As a recommendation, make your enum implement your interface to make the code more readable:
public enum PotatoEnum implements IPotato{
I_WANT_TO_EAT_POTATO(){
#Override
public void eatPotato() {
// Cant put code here.
}},//more ENUMS ;
}
Simply yes
By doing this you are doing something like that:
I_WANT_TO_EAT_POTATO(An object of a virtual class that implments IPotato class);
same as :
I_WANT_TO_EAT_POTATO(Passing any parameter defined by constructor);
See Enum constants as an Inner Classes and you are passing them parameters of their construcors
You can to that. The reason of your mistake is that you have two public identifier (enum and interface) in single file . remove public from enum and it will work
public interface IPotato {
public void eatPotato();
}
enum PotatoEnum {
I_WANT_TO_EAT_POTATO(new IPotato() {
#Override
public void eatPotato() {
// Cant put code here.
}
});
private IPotato _myAnonymousClass;
private PotatoEnum(IPotato anonymousClass) {
this._myAnonymousClass = anonymousClass;
}
public IPotato getPotato() {
return _myAnonymousClass;
}
}
I know that it isn't possible to extend enum in Java, but I am trying to find an elegant solution for the below
I am trying to model enums (or classes) which will contain http end points of various web services across regions, say I have service A and B, each will have 4 region specific end points in US, EU, JP or CN. (This is basically for some seperate debug code that I am writing, in production the end points will be picked from configuration)
I was hoping to do something like this (not compliant java code).
public enum IEndPoint {
NA_END_POINT,
EU_END_POINT,
JP_END_POINT,
CN_END_POINT,
}
public enum ServiceAEndPoint extends IEndPoint {
NA_END_POINT("http://A.com/");
EU_END_POINT("http://A-eu.com/");
JP_END_POINT("http://A-jp.com/");
CN_END_POINT("http://A-cn.com/");
}
I could do this using interfaces where I have a method for each region, but in my opinion the enum way is more expressive, is there any better way I could model this ? What I am looking for is if there is any better way to model the inheritence relation and also having the expressive power of enumerations.
ServiceAEndPoint.NA_END_POINT
vs
serviceAEndPoint.getNAEndPoint()
I'm assuming that you will also want a ServiceBEndPoint enum (and similar). In which case I don't think your model really makes that much sense.
IEndPoint is really an enumeration of the kind of environments/regions where a service might be running. It is not an enumeration of the services themselves. Each individual service (A, B or whatever) will have different addresses for each of the regions.
Therefore I would stick with just the IEndPoint enum, and then in some service-specific code have a lookup map that will give you the address for a given end-point. Something like this:
public enum IEndPoint {
NA_END_POINT,
EU_END_POINT,
JP_END_POINT,
CN_END_POINT,
}
public class ServiceABroker {
private static final Map<IEndPoint, String> addressesByEndPoint;
static {
addressesByEndPoint = new EnumMap<>();
addressesByEndPoint.put(NA_END_POINT, "http://A.com/");
addressesByEndPoint.put(EU_END_POINT, "http://A-eu.com/");
addressesByEndPoint.put(JP_END_POINT, "http://A-jp.com/");
addressesByEndPoint.put(CN_END_POINT, "http://A-cn.com/");
}
public String getAddressForEndPoint(IEndPoint ep) {
return addressesByEndPoint.get(ep);
}
}
If these are static final constants, then just put them in an interface. Name the interface something like IServiceAEndPointKeys, where the keys part is a convention.
Here's where I consider enums to be more appropriate and useful:
Example 1: File type. An enum containing jpg, pdf etc.
Example 2: Column definitions. If I have a table with 3 columns, I would write an enum declaring ID, Name, Description (for example), each one having parameters like column header name, column width and column ID.
Im not sure I understand you question, but you can add methods to an enum for example you could do something like the following:
public enum ServiceAEndPoint{
NA_END_POINT("http://A.com/");
EU_END_POINT("http://A-eu.com/");
JP_END_POINT("http://A-jp.com/");
CN_END_POINT("http://A-cn.com/");
private final String url;
private EndPoint(String url){
this.url=url;
}
public String getURL(){
return url;
}
}
Enums cannot be extended in such a manner, mostly because enums cannot be sub-classed or the constraints they must adhere to will not be possible to impose.
Instead leverage interfaces, like so
public interface IEndPoint;
public enum DefaultEndPoints implements IEndPoint {
NA_END_POINT,
EU_END_POINT,
JP_END_POINT,
CN_END_POINT,
}
public enum DefaultServiceEndPoints implements IEndPoint {
NA_END_POINT("http://A.com/");
EU_END_POINT("http://A-eu.com/");
JP_END_POINT("http://A-jp.com/");
CN_END_POINT("http://A-cn.com/");
}
public void doSomething(IEndPoint endpoint) {
...
}
The reason why one can't subclass in the manner you wish is related to the contract that enums will be both equal via .equals(object) and via ==. If you could subclass, would this make sense?
if ( (DefaultEndPoints)JP_END_POINT == (DefaultServiceEndPoints)JP_END_POINT) {
}
if you say "yes" then I would expect to be able to do this
DefaultEndPoint someEndpoint = DefaultServiceEndPoints.JP_END_POINT;
which would leave a door open for error, as there is no guarantee that a enum entry in one enum declaration is in the other enum declaration.
Could it be different? Perhaps, but it isn't, and changing it would definately introduce a lot of complications that would have to be thoroughly thought out (or it would open avenues to work around Java's strong static-type checking).
You may want to consider something like this:
public abstract class EndpointFactory {
public abstract String getNAEndPoint();
public abstract String getEUEndPoint();
}
public class ServiceAEndpointFactory extends EndpointFactory {
public static final String NA_END_POINT = "http://A.com/";
public static final String EU_END_POINT = "http://A-eu.com/";
public String getNAEndPoint() {
return ServiceAEndpointFactory.NA_END_POINT;
}
public String getEUEndPoint() {
return ServiceAEndpointFactory.EU_END_POINT;
}
}
public class ServiceBEndpointFactory extends EndpointFactory {
public static final String NA_END_POINT = "http://B.com/";
public static final String EU_END_POINT = "http://B-eu.com/";
public String getNAEndPoint() {
return ServiceAEndpointFactory.NA_END_POINT;
}
public String getEUEndPoint() {
return ServiceAEndpointFactory.EU_END_POINT;
}
}
Then you can refer to your strings directly like this:
ServiceAEndpointFactory.NA_END_POINT;
Or, you can use the base object if the type of service is not known until execution:
EndpointFactory ef1 = new ServiceAEndpointFactory();
String ep = ef1.getNAEndPoint();
The drawback of this is the redefinition of the get*Endpoint() functions in each sub-class. You could eliminate that by moving the static final variables to be not static in the base class and putting the getter/setter in the base class only one time. However, the drawback of that is you are not able to reference the values without instantiating an object (which essentially emulates what I find valuable with ENUMs).
How does a pattern like this appeal to you? I let the enum implement an interface and implement the interface in a Debug set and a Release set. The release set can then derive the property name from the enum name - which is neat.
public interface HasURL {
public String getURL();
}
public enum DebugEndPoints implements HasURL {
NA,
EU,
JP,
CN;
#Override
public String getURL() {
// Force debug to go to the same one always.
return "http://Debug.com/";
}
}
public enum NormalEndPoints implements HasURL {
NA,
EU,
JP,
CN;
final String url;
NormalEndPoints () {
// Grab the configured property connected to my name.
this.url = getProperty(this.name());
}
#Override
public String getURL() {
return url;
}
}
I've run into a situation in which I was to extend the functionality of a given class, but I'm not sure of the best way to go about this. I started by invoking functionality "upwards" and have now switched to "downwards", but I see issues with both. Let me explain what I mean. First, the "upwards" approach:
public class ParentValidator
{
public void validate() {
// Some code
}
}
public class ChildValidator extends ParentValidator
{
#Override
public void validate() {
super.validate();
// Some code
}
}
public class GrandchildValidator extends ChildValidator
{
#Override
public void validate() {
super.validate();
// Some code
}
}
This functions perfectly well, but it requires that I always remember to place super.validate() in my method body or the logic in the parent class(es) won't be executed. In addition, extension in this manner can be considered "unsafe" due to the fact that a child class could actually replace/modify the code defined in the parent class. This is what I call invoking methods "upwards" because I'm invoking methods from higher level classes as I go.
To counter these shortfalls, I decided to make ParentValidator.validate() final and have it invoke a different method. Here's what my code was modified to:
public class ParentValidator
{
public final void validate() {
// Some code
subValidate();
}
protected void subValidate() {}
}
public class ChildValidator extends ParentValidator
{
#Override
public final void subValidate() {
// Some code
subSubValidate();
}
protected void subSubValidate() {}
}
public class GrandchildValidator extends ChildValidator
{
#Override
public void subSubBalidate() {
// Some code
subSubSubValidate();
}
protected void subSubSubValidate();
}
This is what I was referring to when I say that I'm calling downwards as each class invokes methods on classes "down" the inheritance chain.
Using this approach, I can be guaranteed that the logic in the parent class(es) will be executed, which I like. However, it doesn't scale well. The more layers of inheritance I have, the uglier it gets. At one level, I think this is very elegant. At two levels, it starts to look shoddy. At three or more, it's hideous.
In addition, just as I had to remember to invoke super.validate() as the first line of any of my children's validate methods, I now have to remember to invoke some "subValidate" method at the end of any of my parent's validate methods, so that didn't seem to get any better.
Is there a better way to do this type of extension that I haven't even touched on. Either of these approaches have some serious flaws and I'm wondering if there's a better design pattern I could be using.
In what you describe as your first approach you are using simple inheritance, your second approach is closer to what the Gang of Four [GoF] called a Template Method Pattern because your parent class is using the so-called Hollywood Principle: "don't call us, we'll call you".
However, you could benefit from declaring the subvalidate() method as abstract in the parent class, and by this, make sure all subclasses are forced to implement it. Then it would be a true template method.
public abstract class ParentValidator
{
public final void validate() {
//some code
subValidate();
}
protected abstract void subValidate() {}
}
Depending on what you are doing there are other patterns that could help you do this in a different manner. For instance, you could use a Strategy Pattern to peform the validations, and by this favoring composition over inheritance, as suggested before, but a consequence is that you will need more validation classes.
public abstract class ParentValidator
{
private final ValidatorStrategy validator;
protected ParentValidator(ValidatorStrategy validator){
this.validator = validator;
}
public final void validate() {
//some code
this.validator.validate();
}
}
Then you can provide specific validation strategies for every type of Validator that you have.
If you want to get the best of both worlds you might considering implementing the solution as a Decorator Pattern where subclasses can extend the functionality of a parent class and still stick to a common interface.
public abstract class ValidatorDecorator implements Validator
{
private final Validator validator;
protected ParentValidator(Validator validator){
this.validator = validator;
}
public final void validate() {
//some code
super.validate(); //still forced to invoke super
this.validator.validate();
}
}
All patterns have consequences and advantages and disadvantages that you must consider carefully.
I'd prefer to 1) program against interfaces, and 2) opt for composition over inheritance. This is how I have done. Some people like it, some do not. It works.
// java pseudocode below, you'll need to work the wrinkles out
/**
* Defines a rule or set of rules under which a instance of T
* is deemed valid or invalid
**/
public interface ValidationRule<T>
{
/**
* #return String describing invalidation condition, or null
* (indicating then that parameter t is valid */
**/
String apply(final T t);
}
/**
* Utility class for enforcing a logical conjunction
* of zero or more validatoin rules on an object.
**/
public final class ValidatorEvaluator
{
/**
* evaluates zero or more validation rules (as a logical
* 'AND') on an instance of type T.
**/
static <T> String apply(final T t, ValidationRule<T> ... rules)
{
for(final ValidationRules<T> v : rules)
{
String msg = v.apply(t);
if( msg != null )
{
return msg; // t is not valid
}
}
return null;
}
}
// arbitrary dummy class that we will test for
// i being a positive number greater than zero
public class MyFoo
{
int i;
public MyFoo(int n){ i = n; }
///
}
public class NonZeroValidatorRule implements ValidatorRule<MyFoo>
{
public String apply(final MyFoo foo)
{
return foo.i == 0 ? "foo.i is zero!" : null;
}
}
// test for being positive using NonZeroValidatorRule and an anonymous
// validator that tests for negatives
String msg = ValidatorEvaluator.apply( new MyFoo(1),
new NonZeroValidatorRule(),
new ValidatorRule<MyFoo>()
{
public String apply(final MyFoo foo)
{
return foo.i < 0 ? "foo.i is negative!" : null;
}
}
);
if( msg == null )
{
\\ yay!
...
}
else
{
\\ nay...
someLogThingie.log("error: myFoo now workie. reason=" + msg );
}
More complex, non-trivial evaluation rules can be implemented this way.
The key here is that you should not use inheritance unless there exists a is-a relationship. Do not use it just to recycle or encapsulate logic. If you still feel you need to use inheritance, then don't go overkill trying to make sure that every subclass executes the validation logic inherited from the superclass. Have implementations of each subclass do an explicit execution on super:
public class ParentValidator
{
public void validate() { // notice that I removed the final you originally had
// Some code
}
}
pubic class ChildValidator extends ParentValidator
{
#Override
public void validate() {
// Some code
super.validate(); // explicit call to inherited validate
// more validation code
}
}
Keep things simple, and don't try to make it impossible or fool-proof. There is a difference between coding defensively (a good practice) and coding against stupid (a futile effort.) Simply lay out coding rules on how to subclass your validators. That is, put the onus on the implementors. If they cannot follow the guidelines, no amount of defensive coding will protect your system against their stupidity. Ergo, keep things clear and simple.
I prefer to using composition over inheritance if your subSubSubValidate is related general functionality. You can extract new class and move it there than you can use it without inheritance in the other classes.
There is also
"Favor 'object composition' over
'class inheritance'." (Gang of Four
1995:20)
maybe a look at the visitor pattern may help you to develop your pattern.
Here are some information on it : http://en.wikipedia.org/wiki/Visitor_pattern