【问题标题】:Subclassing an enum子类化枚举
【发布时间】:2011-01-05 14:12:16
【问题描述】:

有没有一种简单的方法来继承 Java enum

我问这个是因为我喜欢其中的 10 个实现相同的接口,但它们对某些方法也有相同的实现,所以我想通过将所有相同的实现放在扩展 Enum 的中间对象中来重用代码它也是我需要的所有其他人的超类。

也许没有我想的那么简单?

提前致谢

【问题讨论】:

    标签: java inheritance enums


    【解决方案1】:

    你不能这样做,因为语言不允许你这样做。并且出于一个很好的逻辑原因:仅当您可以从子类中删除一些枚举值而不是添加新的枚举值时,对枚举进行子类化才有意义。否则你会破坏Liskov Substitution Principle

    简而言之,只要期望超类的实例,子类的每个实例都应该是可以接受的。如果你在枚举子类中添加一个新的枚举成员,那显然不能被只知道超级枚举的人接受。

    有关更多详细信息和可能的替代方案,请参阅this earlier answer of mine

    在您的具体情况下,@Jason 的建议可能会提供一个很好的解决方案(为他 +1 :-)

    更新@OrangeDog 的评论

    好点,我在上面有点草率 :-) 在实施方面你是对的。但是,从逻辑的角度来看,枚举类型完全由其有效值的集合来描述。通常,适当的子类是其超类的特化。换句话说,有效的子类实例集(应该)始终是超类实例集的子集(每只狗都是动物,但不是每只动物都是狗。)

    【讨论】:

    • 不完全正确。枚举值在内部是枚举“类”的一个实例。 SubEnum 中的值可以很容易地作为 SuperEnum 传递,并且您可以在其上调用 SuperEnum 的所有方法。您只是无法获得与其比较相等的 SuperEnum 实例(所有类的身份平等都是如此)。
    • “出于一个很好的逻辑原因:只有当你可以从子类中删除一些枚举值而不是添加新的枚举值时,对枚举进行子类化才有意义。否则你会违反 Liskov 替换原则。”那是错的。例如,如果您使用一些已实现的泛型方法创建了一个父枚举,那么扩展一个枚举将是完美的选择。
    • 请注意,您可以创建枚举的匿名子类,如下所示:enum E { INSTANCE {} }E.INSTANCE.getClass() == E.class 将评估为假。 (但我意识到这通常没有什么帮助。)
    • @Johan,一般来说,子类化意味着专门化,换句话说,限制类型中可能值的集合。狗是动物的一个子类型,而不是相反。对于枚举类型,添加新值显然与这个概念相矛盾。我知道这听起来不合逻辑(对我来说也是如此),但请仔细考虑。
    • @Péter Török 这取决于您想做什么以及如何去做。也许您仅限于 Dog 但希望 Animal 和 Animal 丢失。枚举非常有限,您想制作自己的超级枚举来使用。所以是的,它会是一个扩展的子类,但不会被用作它。
    【解决方案2】:

    我问这个是因为我喜欢其中的 10 个实现相同的接口,但它们对某些方法也有相同的实现,所以我想通过将所有相同的实现放在扩展 Enum 的中间对象中来重用代码也是我需要的所有其他人的超类。

    使用静态帮助类怎么样?

    interface Animal
    {
        public void speak();
    }
    
    class AnimalHelper
    {
        public static void speakHelper(Animal animal) {
            // common methods here
        }
    }
    
    enum Dog implements Animal { SCHNAUZER, LABRADOR, ST_BERNARD, DACHSHUND;
        @Override public void speak() {
            AnimalHelper.speakHelper(this);
        }
    };
    
    enum Bird implements Animal { OWL, FINCH, DUCK, GOOSE; }
        @Override public void speak() {
            AnimalHelper.speakHelper(this);
        }
    };
    

    【讨论】:

    • 是的。但如果每个枚举都具有所有公共属性,则构造函数、getter 和 setter 中的重复是显而易见的。如果你可以看看我的问题:stackoverflow.com/questions/31473115/…
    【解决方案3】:

    使用 Java 8,您可以使用 default methods 将共享实现放入接口中。

    public class DefaultMethodOnEnumInterface {
    
        public interface Greeter {
    
            default public void greet() {
                System.out.println("Hello, world!");
            }
        }
    
        public enum Greeters implements Greeter {
            A,
            B;
        }
    
        public static void main(String[] args) {
            Greeters.A.greet();
            Greeters.B.greet();
        }
    }
    

    如果需要访问Enum类实现的方法,则在接口中添加签名:

    public interface Greeter {
    
        default public void greet() {
            System.out.println("Hello, world! This is " + name());
        }
    
        /**
         * @see Enum#name()
         */
        public String name(); // implemented by Enum
    }
    

    【讨论】:

      【解决方案4】:

      尝试使用 Apache commons 包中的 Enums,您可以在其中子类化 Enums。 不知道对你有没有帮助。

      【讨论】:

        【解决方案5】:

        虽然在 Java 中有 proposals for abstract enums,但其收益被认为太低而无法超过成本。你必须坚持转发方法调用。

        【讨论】:

          【解决方案6】:

          该语言不允许您这样做,因为枚举旨在有效地表示枚举值,而不是用于实现代码。尝试使用另一种模式,例如静态帮助程序(实用程序)类。

          【讨论】:

          • "不用于实现代码" -- 错误!您可以在枚举类和每个枚举实例中做很多有用的事情。你不能继承枚举。 Enum 框架旨在生成类型安全的单例。
          • @Jason - “专为”,而不是“只让你”
          • Java 的枚举经过精心设计,允许枚举类和实例中的方法。
          • @Jason - 我的意思是设计师的思考过程是“我们有封装方法的类,现在我们需要枚举来封装枚举的常量值”而不是“我们有封装方法的类,现在我们需要枚举来封装方法”
          • 啊,明白了。换句话说,枚举首先被设计为封装枚举常量值的安全单例,当他们这样做时,他们对其进行了一些思考,以赋予它们一些良好的面向对象的特性。
          【解决方案7】:

          @Jason S 给出了很好的回复,但是静态方法让你失去了 OOP 的潜力。

          委托呢?我的意思是:

          1. 定义一个通用接口“I_A”,您可以在其中定义所有 getter/setter 和所有其他方法。

          2. 定义一个“struct-like”类“S_C”:它只实现getter和setter,其他方法都是空的,因为没用。

          3. 1234563 ,感谢 Java 的默认方法,将 getter/setter 定义为调用委托者的 getter/setter。
          4. 您的所有枚举都实现了“I_A_Delegating”并具有“S_C”的本地实例

          代码示例:

          public class EnumFakeExtension{
               /**"I_A"*/
               public static interface CommonInterface{
                     public Object getFieldOne();
                     public Object getFieldTwo();
          
                     public void setFieldOne(Object o);
                     public void setFieldTwo(Object o);
          
                     public void someMethod();
               }
          
               /*"S_C"*/
               public static class CommonDelegator_FieldKeeper implements CommonInterface{
                   Object oOne, oTwo;
                     public Object getFieldOne(){ return oOne; }
                     public Object getFieldTwo(){ return oTwo; }
          
                     public void setFieldOne(Object o){ oOne = o; }
                     public void setFieldTwo(Object o){ oTwo = o; }
          
                     public void someMethod(){ /*empty*/ }
               }
          
          
               /**"I_A_Delegating"*/
               public static interface CommonInterface_Delegating extends CommonInterface{
                   public CommonInterface getDelegate();
                   public void setDelegate(CommonInterface delegator);
          
                   /**Just to simplify*/
                   public default void setDefaultDelegate(CommonInterface delegator){
                       setDelegate( new CommonDelegator_FieldKeeper() );
                   }
          
          
                   public default Object getFieldOne(){ return getDelegate().getFieldOne(); }
                   public default Object getFieldTwo(){ return getDelegate().getFieldTwo(); }
          
                   public default void setFieldOne(Object o){ getDelegate().setFieldOne(o); }
                   public default void setFieldTwo(Object o){ getDelegate().setFieldTwo(o); }
               }
          
          
              /*the enums, now*/
          
              public static enum EnumFirst implements CommonInterface_Delegating{
                  FieldA, FieldB, FieldC;
          
                  EnumFirst (){
                      setDefaultDelegate();
                  }
                  final CommonDelegator_FieldKeeper delegator;
          
                  public CommonInterface getDelegate(){ return delegator; }
                  public void setDelegate(CommonInterface delegator){ this.delegator=delegator; }
          
          
                  public void someMethod(){
                      /*do what You need*/
                  }
              }
          
          
              public static enum EnumSecond implements CommonInterface_Delegating{
                  FieldA, FieldB, FieldC;
          
                  EnumSecond (){
                      setDefaultDelegate();
                  }
                  final CommonDelegator_FieldKeeper delegator;
          
                  public CommonInterface getDelegate(){ return delegator; }
                  public void setDelegate(CommonInterface delegator){ this.delegator=delegator; }
          
                  public void someMethod(){
                      /*do what You need, again*/
                  }
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-03-24
            • 2013-04-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-05-31
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多