Usage of Class and Enum Inside an Interface

Introduction

This small article provides an outline of the usage of classes and enums inside an interface that seem to be unusual to a developer. I recently was interviewing for candidates and I asked the basic question of whether we can declare enums and classes inside an interface. Most candidates said "NO" but the answer is "Yes" . There is no hard and fast rule that, for a specific situation or specified circumstance we need to use it. Some developers argue that that it is not a professional way to do it, some argue that we can do it but novice developers will not be able to understand and some argue that as part of good design principle we should use it. Let us not debate the details of the design, rather we need to learn it so that if necessary we will use it. Java provides a way for us to define classes and enums inside an interface. As you know, that interface provides a path to abstraction, why can't we extend the abstraction even further? There may be some functional aspects for which you can define enums and classes inside an interface and if you take a broader look, it looks very elegant.

Technicalities

If you are working on a project or product development, it is always necessary to understand the functionalities and thereby put the design principles accordingly. In all software products it is always necessary to define the error code and error message while dealing with various fields. If you issue an error code and the message to the customer in an elegant way then it will increase the popularity of your project or product . Let us decide how to define the errors. While dealing with functional errors , some designers put all the error codes and error messages (constants) in a properties file or XML file, some put them at class level and some put them in an interface. If you are not dealing with the international languages then you can define all error codes and descriptions in a class or at interface level. If you define all the error codes in an interface and want to use a constant type of interface then do not implement that interface in any class, it becomes heavy. However it is considered a good practice to define all the error codes and descriptions in an interface. Let us learn that interfaces are also used as constants and as a namespace apart from its normal usage. Let us see in the following how interfaces are used as constants and namespaces below.

Constant Interface

It is considered as a good practice to define all the error codes in an interface and all the error descriptions at class level. Let us see the code below.

public interface ApplicationErrors
{
    public static final int ERR_INVALID_EMAIL = 990001;
 
}


In the preceding example we have defined the error code, now where shall we define the description for that error code? If you define the description with a String type message then it will create confusion among the developers which one to use. Think about a situation where you have an Excel sheet describing both error codes and descriptions and you want to develop your product based on that Excel sheet. If you want to put all the descriptions in a class then other developers will write their own classes for the other descriptions and that is not a good way. Always remember that there should be a single point of view or called contact for error codes and descriptions or error messages. In other words there should be a consolidated point of contact for error codes and descriptions that will increase the readability and the accessibility and it helps in the case of further maintenance. This is one of the required reasons why developers generally put all the error messages inside a class that is inside the interface. In an application there can be various categories of errors which will see in the next section. Let us see the code below.

public interface ApplicationErrors

{

public static final int ERR_INVALID_EMAIL = 990001;

public class ErrorMsg

{

       public static final String ERR_INVALID_EMAIL = "Invalid Email Id";
}

 

}

In the code above you will get both error code and error message in a single unit where the name of the identifier is the same but of a different type. It is easier to use in your application. The keyword "ERR_INVALID_EMAIL" serves the dual purpose as it provides the error code and also description. The usage is given below.

System.out.println(ApplicationErrors.ERR_INVALID_EMAIL + "-----"
+ ApplicationErrors.ErrorMsg.ERR_INVALID_EMAIL);

In the preceding case it is clear that error codes are part of the interface whereas error messages are part of the Msg class that is inside the interface.

Similarly you can define enums inside an interface that provide a good design. Let me provide the following the code view.
 

public interface AppErrors

{

public enum ErrorType

{

       ERR_INVALID_EMAIL("1234")

{

 

             @Override

             public String getMsg()

        {

        }

       };

       private ErrorType(String errCode)

    {

    }

       private String errCode;

       public String getCode()

    {

    }

};

}

The code above is just a skeletal structure and its use is given below.

System.out.println("Error Code : "
                           + AppErrors.ErrorType.ERR_INVALID_EMAIL.getCode());
             System.
out.println("Error Msg :"
                           + AppErrors.ErrorType.ERR_INVALID_EMAIL.getMsg());

Namespace Interface

Sometimes interfaces are used like namespaces. Let me provide you an example, there are two types of cards, like Debit Card and Credit Card. Each card has card type information, more specifically Credit Card has a minimum and a maximum credit limit, similarly a Debit Card has a maximum withdrawl limit and there can be other types of information also. Can we consider a Credit Card and a Debit Card to be different namespaces where the card type information gives a different view? Yes it will be good from a design perspective. There can be many arguments or debates about why we are defining them as namespaces. However if it so then we need to define enums inside the interfaces. Let us see the code below.
 

public interface CreditCard {

       public String getCardInfo();

       public void setMinLimit(long value);

       public long getMinLimit();

       public enum CardType {

             /** The platinum. */

             PLATINUM("PL", 1000000L) {

                    @Override

                    public long getMaxValue() {

                           return 1000000L;

                    }

             },

             /** The gold. */

             GOLD("GL", 500000L) {

                    @Override

                    public long getMaxValue() {

                           return 500000L;

                    }

             },

             /** The silver. */

             SILVER("SL", 100000L) {

                    @Override

                    public long getMaxValue() {

                           return 100000L;

                    }

 

             };

//~~ Other codes below.

       }

}

There can be multiple implementations of the Credit Card interface for various types of banks, but each bank can have only three types of Credit Cards, they are Platinum, Silver and Gold. The following code snippet displays the use of the preceding interface:

CreditCard cc = new CreditCardImpl("1234", "Deba", "PL");

cc.setMinLimit(5000);

System.out.println("Card Details : " + cc);

System.out.println("Credit Card Min Limit : " + cc.getMinLimit());

System.out.println("Card Info : " + cc.getCardInfo());

Configuration

To have a clear understanding and usage of the preceding concepts, download the source code from dropbox "https://www.dropbox.com/s/a2v1d8irr4mntv1/classenuminsideinterface.zip ". Configure the project in the Eclipse editor.

Refer to the following interfaces as a constant and/or a namespace:

CreditCard.java
DebitCard.java
AppErrors.java
ApplicationErrors.java

Refer to the following classes for various types of uses:

CreditCardImpl.java
DebitCardImpl.java
EmailException.java
EmailException1.java

Refer to the following classes as a test harness.

TestAppErrors.java
TestCreditCard.java
TestDebitCard.java
TestEmailValidation.java
TestError.java

Conclusion

I hope you have enjoyed my small article about the rare usage of interfaces. Download the complete project and go through the source code to understand the concept and its usage. Based upon the complexity and design, you can decide whether to use this concept. For any kinds of issues and errors you can contact me at debadatta.mishra@gmail.com.