0

I know it is possible to declare 3 level enums in style of A.B.C using B as interface and finally C as enum member which implements this interface.

But I'd like to nest several enums to map constant tree structure with fixed number of members. And of course something like Tree.A.Leaf.B.Node.C.Something.D or simple A.B.C.D looks nice. Is it possible? Cannot find any way to implement it. Thank you.

UPDATE (resulting solution):

  • Enums are really bad for this case, thank for everyone convincing me.
  • Finally I've build solution based on static classes with private constructors and static fields.

Example code is placed as my own answer to keep question clear. Hope this will help somebody else.

Roman Nikitchenko
  • 12,800
  • 7
  • 74
  • 110
  • 1
    You think that looks nice? – Sotirios Delimanolis Oct 03 '13 at 18:54
  • Yes if structure is constant. Do you have alternative proposition? – Roman Nikitchenko Oct 03 '13 at 18:54
  • *looks nice??* -> Check this out - `enum A { X; enum B { Y; enum C { Z; enum D { } } } }`. This how the structure would look like. Step away. – Rohit Jain Oct 03 '13 at 18:56
  • @RohitJain: Defining it is ugly, but using it should be trivial. – Robert Harvey Oct 03 '13 at 19:00
  • @RobertHarveyUmm. Right it might not be that difficult to use it. – Rohit Jain Oct 03 '13 at 19:04
  • 1
    yes, see these answers: http://stackoverflow.com/questions/2636845/how-to-nest-an-enum-inside-the-value-of-an-enum/8960269#8960269 http://stackoverflow.com/questions/7296785/using-nested-enum-types-in-java/7399540#7399540 http://stackoverflow.com/questions/8732710/enum-within-an-enum/8941089#8941089 http://stackoverflow.com/questions/10233099/id3-java-enum-tree/10234825#10234825 – Ray Tayek Oct 03 '13 at 23:39

2 Answers2

2
    enum Foods{  
      drinks, eats;     

     enum Drinks {   
        apple_juice, cola;  

      }  

      enum Eats{   
          potatoe, rice;  

    } 


} 

Try printing: Foods.Eats.rice

But it looks bad and tastes yucks!!

Sage
  • 15,290
  • 3
  • 33
  • 38
  • Could you please point to better alternatives? But I don't like just `Foods.get("eat").get("rice")`. – Roman Nikitchenko Oct 04 '13 at 06:58
  • 1
    what about using class with static constants? – Sage Oct 04 '13 at 07:33
  • sage, +1 for static constants. Actually final solution is just reviewed inside team and it is based on static nested classes and static members with private constructors. Schema is fixed and nobody can add anything and it is pretty nice. – Roman Nikitchenko Oct 04 '13 at 15:39
0

Final solution code (with some simplification to keep things clear) with illustration of using it (look inside main() method). This is what I was searching for.

package com.test;

/*
 * Umbrella class which defines whole DB schema structure and some of global operations.
 **/
public class Schema {

    /**
     * Schema elements are open for those who need access to them on appropriate level
     * (HBase API). It should be encapsulated by business logics as development progresses
     * but there's always something which is not covered so we keep them open.
     *
     * Schema elements are obviously something which gives
     * you access to its string name and name prepared to be used by HBase.
     */
    public interface NamedEntityInterface {

        /**
         * Just receive name as it is used by DB.
         * @return DB level name as string.
         */
        public abstract String getName();

        /**
         * @return DB level name to be used for HBase API calls.
         */
        public abstract byte[] getNameBytes();

    }

    /**
     * NamedEntity class provides most generic implementation for NamedEntityInterface
     * widely used through all the schema.
     */
    public abstract static class NamedEntity implements NamedEntityInterface {

        private final String name;
        private final byte[] nameBytes;

        private NamedEntity(String name) {
            this.name = name;
            this.nameBytes = name.getBytes();
        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public byte [] getNameBytes() {
            return nameBytes;
        }
    }

    /**
     * Column abstraction.
     */
    public static class Column extends NamedEntity {

        private Column(String name) {
            super(name);
        }
    }

    /**
     * Column family abstraction.
     */
    public static class Family extends NamedEntity {

        static final String NAME_DEFAULT = "d";

        private Family(String name) {
            super(name);
        }
    }

    /**
     * Table abstraction.
     */
    public static class Table extends NamedEntity {

        private Table(String name) {
            super(Schema.class.getPackage().getName() + '.' + name);
        }
    }

    public static class TableA extends Table {

        public static class FamilyDefault extends Family {

            private FamilyDefault() {
                super(Family.NAME_DEFAULT);
            }

            public static final Column a = new Column("b");
            public static final Column b = new Column("a");
        }

        private TableA() {
            super("table.A");
        }

        public static final FamilyDefault familyDefault = new FamilyDefault();
    }

    public static class TableB extends Table {

        public static class FamilyA extends Family {

            public static final Column a = new Column("a");
            public static final Column b = new Column("b");

            private FamilyA() {
                super(NAME_DEFAULT);
            }
        }

        public static class FamilyB extends Family {

            private FamilyB() {
                super("f");
            }
        }

        private TableB() {
            super("table.B");
        }

        public static final FamilyA familyA = new FamilyA();
        public static final FamilyB familyB = new FamilyB();
    }

    static public TableA tableA = new TableA();
    static public TableB tableB = new TableB();

    public static void main(String [] args) {

        String tableName = Schema.tableA.getName();
        Family someFamily = Schema.tableA.familyDefault;
        byte [] column = Schema.tableA.familyDefault.a.getNameBytes();

        String tableBFamilyBName = Schema.tableB.familyB.getName();

        System.out.println("name: " + tableBFamilyBName);
    }
}
Roman Nikitchenko
  • 12,800
  • 7
  • 74
  • 110