DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Building a Rust Command Line Interface to Chat With Llama 3.2
  • A Beginner’s Guide to GraphQL Interfaces and Unions
  • Contexts in Go: A Comprehensive Guide
  • The Power of Refactoring: Extracting Interfaces for Flexible Code

Trending

  • Unlocking the Benefits of a Private API in AWS API Gateway
  • Top Book Picks for Site Reliability Engineers
  • Integrating Security as Code: A Necessity for DevSecOps
  • Medallion Architecture: Why You Need It and How To Implement It With ClickHouse

Extensible Enum With Interface

Everyone knows you can't extend Enums, right? Well, with some coding magic, it turns out how can. See how to make Enums extensible with Interface's help.

By 
Shamik Mitra user avatar
Shamik Mitra
·
Oct. 15, 16 · Tutorial
Likes (26)
Comment
Save
Tweet
Share
95.4K Views

Join the DZone community and get the full member experience.

Join For Free

In Java, Enum is a powerful data type. There are a lot of places you can use Enum to take advantage of it, like in a Static Factory method. There, it's a wise decision to pass the Enum type rather than passing a String. Below, I mention some situations where using Enum is advantageous.

Enum Advantages

    1. In a Static Factory method, passing Enum as an argument makes the method typesafe. Method users can’t pass an arbitrary value to this method.
    2. Instead of using bit fields, using Enum and EnumSet makes the code cleaner and easy to maintain.
    3. Using Enum can achieve a Singleton pattern, which is inherently Thread Safe.
    4. You can also use them to get rid of If/Switch statements.

Although Enum has several advantages, it has one major disadvantage. We cannot extend Enum.

So the Question is, “Can we extend Enum, and ehen it is needed?”

Yes we can emulate the extensibility in Enum, but we have to do it in a strategic way.

We know that Enum can’t be extended, but we know the fact that an Interface can be implemented and Enum can implement the Interface. So, combining these two statements, we can achieve extensibility. Where Enum can’t be extended, if we use the “Coding to an Interface” Strategy, we can easily replace BaseType Enum with our Extended Enum.

Now coming to the use case:

According to Joshua Bloch, “There is at least one compelling use case for extensible enumerated types, which is operation codes, also known as opcodes. An opcode is an enumerated type whose elements represent operations on some machine, such as the Operation. Sometimes, it is desirable to let the users of an API provide their own operations, effectively extending the set of operations provided by the API.”

According to Josh Bloch, in the case of an operation, we can provide some basic operations in an Enum — like plus/minus in a simple calculator — but if API users want more, like a square root operation, they can achieve it through extending the Operation Interface and create a new Enum.

Steps For Achieving Extensibility

Let’s take a use case where we have an Enum called Direction in an API. It has entries for NORTH, SOUTH, EAST, and WEST. In most cases, API users use these basic directions, but when it is about to show the shortest path between the source and the destination, API users need some advanced direction, like NORTH-EAST, NORTH-WEST, etc.

How can we judiciously implement the API so users can have the option to extend the Basic Direction Enum?

Steps

    1. Create an Interface called Direction and declare a method called showDirection().
    2. Create a BasicDirection Enum by implementing Direction.
    3. Put entries for NORTH, SOUTH, EAST, and WEST.
    4. Please note that as it implements the Direction interface, each Enum has to override the showDirection method.
    5. Create an AdvanceDirection Enum with NORTH-EAST, NORTH-WEST, etc. entries.
    6. Use this Custom Enum/Basic Enum anywhere interchangeably.

Java Code

Direction Interface

package com.example.enumtest;

public interface Direction {
    public void showDirection();
}


BasicDirection Enum

package com.example.enumtest;

public enum BasicDirection implements Direction {

    NORTH {
        @Override
        public void showDirection() {
            System.out.println("I am NORTH");
        }
    },

    SOUTH {
        @Override
        public void showDirection() {
            System.out.println("I am South");
        }
    },

    EAST {
        @Override
        public void showDirection() {
            System.out.println("I am EAST");
        }
    },

    WEST {
        @Override
        public void showDirection() {
            System.out.println("I am WEST");
        }
    }
}

AdvanceDirection Enum

package com.example.enumtest;

public enum AdvanceDirection implements Direction {
    NORTHEAST {
        @Override
        public void showDirection() {
            System.out.println("I am NORTH-EAST");
        }
    },

    NORTHWEST {
        @Override
        public void showDirection() {
            System.out.println("I am NORTH-WEST");
        }
    },

    SOUTHEAST {
        @Override
        public void showDirection() {
            System.out.println("I am SOUTH-EAST");
        }
    },

    SOUTHWEST {
        @Override
        public void showDirection() {
            System.out.println("I am SOUTH-WEST");
        }
    }
}

DirectionDriver Class 

package com.example.enumtest;
public class DirectionDriver {
    public static void printDirection(Direction op)
    {
        op.showDirection();
    }

    public static <T extends Enum<T> & Direction> void  printDirections(Class<T> clazz)
    {
        for(Direction direction : clazz.getEnumConstants())
        {
            direction.showDirection();
        }
    }

    public static void main(String[] args) {

        DirectionDriver.printDirection(BasicDirection.EAST);
        DirectionDriver.printDirection(AdvanceDirection.SOUTHWEST);

        DirectionDriver.printDirections(BasicDirection.class);
        DirectionDriver.printDirections(AdvanceDirection.class);

    }
}


Output

I am EAST
I am SOUTH-WEST
I am NORTH
I am South
I am EAST
I am WEST
I am NORTH-EAST
I am NORTH-WEST
I am SOUTH-EAST
I am SOUTH-WEST

Please pay attention to the class DirectionDriver, where I create two methods

  • printDirection, which takes Direction as the input, and I pass an Enum entry to it.

  • Another version is that the printDirection method prints all Enum entries. To achieve that, I make a generic type that says T must be an Enum and a subtype of Direction by <T extends Enum<T> & Direction>, then pass the class instance so I can iterate over EnumConstants.

Interface (computing)

Published at DZone with permission of Shamik Mitra, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Building a Rust Command Line Interface to Chat With Llama 3.2
  • A Beginner’s Guide to GraphQL Interfaces and Unions
  • Contexts in Go: A Comprehensive Guide
  • The Power of Refactoring: Extracting Interfaces for Flexible Code

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!