Multiple enums vs One enum

I was looking at the example implementation of Publisher (AsyncIterablePublisher.java) of the reactive-streams spec when I stumbled into something that I don't understand why it was done that way.

static interface Signal {};
enum Cancel implements Signal { Instance; };
enum Subscribe implements Signal { Instance; };
enum Send implements Signal { Instance; };

Being realistic that I'm not such an advanced programmer as the person that wrote this I'm sure that there is a reason to do it that way. But I'm also not able to explain why it would be better than doing this (which is how I would have done it).

enum Signal {
  Cancel,
  Subscribe,
  Send;
}

Could someone explain it to me why it would be better? Advantages / disadvantages?


Do not be too strict, here is my interpretation of this code. Let us call the owner of reactive-streams Roland.

At first Roland needs a Common Interface for all inboundSignals

static interface Signal {};

ConcurrentLinkedQueue<Signal> inboundSignals = new ConcurrentLinkedQueue<Signal>();

Signals like Cancel , Subscribe and Send have allways the same purpose are immutable and occur very frequently, so it is good Idea to implements they as Joshua Bloch's Singleton:

enum Cancel    implements Signal { Instance; };
enum Subscribe implements Signal { Instance; };
enum Send      implements Signal { Instance; };

the other way to do the same is similar to your proposal and my favorite:

enum CommonSignals implements Signal{

    Cancel {
        @Override
        void debug() {
            System.out.println("Cancel");
        }
    },

    Subscribe {
        @Override
        void debug() {
            System.out.println("Subscribe");
        }
    },

    Send {
        @Override
        void debug() {
            System.out.println("Send");
        }
    };

    abstract void debug();

    [...] some other methods I could need in the future
}

As you can see, this is a different implementation. But the idea is the same - Signal as singleton

We move on and find this code:

static final class Request implements Signal {
    final long n;
    Request(final long n) { // every Request has different value of n
        this.n = n;
    }
};

Since inboundSignals can contain multiple Request objects it is not possible to implement this type of Signal as Singleton. Therefore it can not be a member of CommonSignals or implemented as enum .


Conclusion

Roland used one of many possibilities to implement a singletons. I think that's more a matter of taste how to do it.


For the type of usage in AsyncIterablePublisher the two forms are equivalent, and arguably the latter, one enum with multiple constants, is more natural.

Actually, the former form is very rare. I can see one argument in favor of using it (but being so rare it means that this point is usually not that important): when you define each constant in its own enum you get a chance to define different methods/fields, such as:

enum Cancel implements Signal { Instance; };
enum Send implements Signal { 
  Instance; 
  public void someSendSpecificMethod() { ... }
}

so you can now do Send.Instance.someSendSpecificMethod() . Very awkward, very rare.


The difference is that you can add another instances of Signal without changing the original enum. Your code can work with Signal instances and different types can be supplied. The same as interface for classes - gives you flexibility but it is useful only if you need it. In your case I don't see much use because the interface is empty and the enums implementing it have nothing in them.

You can check this site for a good example of enum with interfaces:

http://www.selikoff.net/2011/06/15/java-enums-can-implement-interfaces/

链接地址: http://www.djcxy.com/p/85196.html

上一篇: CircleCI:涉及时间戳的规格错误

下一篇: 多个枚举vs一个枚举