如何为几个 Java 枚举添加常用方法?(抽象类祖先?)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11163968/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 04:02:03  来源:igfitidea点击:

How to add common methods for a few Java enums? (abstract class ancestor?)

javaoopinheritanceenums

提问by zggame

I have a few Java enums as such

我有一些 Java 枚举

public enum Aggregation
{
    MORTGAGE( "Mortgage" ),
    POOLS( "Pools" ),
    PORTFOLIO( "Portfolio" );

    private Aggregation( final String name )
    {
        m_Name = name;
    }
    private String m_Name;
    static Map< String, Aggregation > c_LOOKUP =
        new HashMap< String, Aggregation >();
    static {
        for (Aggregation agg:values()){
            c_LOOKUP.put(agg.m_Name,agg);
        }
    }

    public Aggregation lookup(String name){
        return c_LOOKUP.get( name );
    }

    @Override
    public String toString()
    {
        return m_Name;
    }
}

public enum Interval
{
    MONTHLY( "Monthly" ),
    QUARTLY( "Quartly" ),
    SEMIANNUALLY( "SemiAnnually" ),
    ANNUALLY("Annually");

    private Interval( final String name )
    {
        m_Name = name;
    }
    private String m_Name;
    static Map< String, Interval > c_LOOKUP =
        new HashMap< String, Interval >();
    static {
        for (Interval agg:values()){
            c_LOOKUP.put(agg.m_Name,agg);
        }
    }

    public Interval lookup(String name){
        return c_LOOKUP.get( name );
    }

    @Override
    public String toString()
    {
        return m_Name;
    }
}

As you can see, there are quite some code duplication here. It would be nice if there is a way to introduce something like an abstract common ancestor class. But java enum cannot inherent. What would be the best approach? Thanks.

如您所见,这里有相当多的代码重复。如果有一种方法可以引入抽象公共祖先类之类的东西,那就太好了。但是java枚举不能固有。最好的方法是什么?谢谢。



Edit: I have work out a version similar to ?ukaszBachman and missingfacktor

编辑:我制定了一个类似于 ?ukaszBachman 和 missingfacktor 的版本

static public enum Aggregation
{
    MORTGAGE( "Mortgage" ),
    POOLS( "Pools" ),
    PORTFOLIO( "Portfolio" );

    private final String m_Name;

    final static private ReverseDictionary< Aggregation > c_DICTIONARY =
        new  ReverseDictionary< Aggregation >( Aggregation.class );

    static public Aggregation lookup( final String name )
    {
        return c_DICTIONARY.lookup( name );
    }

    private Aggregation( final String name )
    {
        m_Name = name;
    }

    @Override
    public String toString()
    {
        return m_Name;
    }
}

static public enum Interval
{
    MONTHLY( "Monthly" ),
    QUARTLY( "Quartly" ),
    SEMIANNUALLY( "SemiAnnually" ),
    ANNUALLY( "Annually" );

    private final String m_Name;
    final static private ReverseDictionary< Interval > c_DICTIONARY =
        new ReverseDictionary< Interval >( Interval.class );

    static public Interval lookup( final String name )
    {
        return c_DICTIONARY.lookup( name );
    }

    private Interval( final String name )
    {
        m_Name = name;
    }

    @Override
    public String toString()
    {
        return m_Name;
    }
}


static public class ReverseDictionary< E extends Enum< E >>
{
    Map< String, E > c_LOOKUP = new HashMap< String, E >();

    public ReverseDictionary( final Class< E > enumClass )
    {
        for( final E agg : EnumSet.allOf( enumClass ) )
        {
            c_LOOKUP.put( agg.toString(), agg );
        }
    }

    public E lookup( final String name )
    {
        return c_LOOKUP.get( name );
    }

}

I see some reasoning. However, it is still not very satisfactory.

我看到一些推理。然而,它仍然不是很令人满意。

  1. It is hard to define the interface for lookup(String)because of the different return type
  2. I can appreciate that the lookup(String)is not really duplication but a specification, but I am still feel that m_Name field and the toString() logic is a bit redundant. We are really specifying one category of enum, and it seems to be "is-a"relationship in my opinion.
  1. lookup(String)由于不同的返回类型,很难定义接口
  2. 我可以理解这lookup(String)不是真正的重复而是规范,但我仍然觉得 m_Name 字段和 toString() 逻辑有点多余。我们确实指定了一类枚举,在我看来它似乎是“is-a”关系。

回答by ?ukaszBachman

Favor composition over inheritanceand programming for the sake of interfaces. Since Enums are classes (not regular, but still - classes) you can create some field containing shared logic, let the enum implement you interface and delegate implementation to this field.

为了接口,更喜欢组合而不是继承编程。由于枚举是类(不是常规的,但仍然是类),您可以创建一些包含共享逻辑的字段,让枚举实现您的接口并将实现委托给该字段。

Relevant code snippets:

相关代码片段:

Shared interface

共享接口

public interface MyInterface {

    void someMethod();

}

Logic implementation

逻辑实现

public class MyInterfaceImpl implements MyInterface {

    public void someMethod() {
        System.out.println("Do smth...");
    }

}

First enum

第一个枚举

public enum EnumA implements MyInterface {
    ;

    private MyInterface impl = new MyInterfaceImpl();

    public void someMethod() {
        impl.someMethod();
    }

}

Second enum

第二个枚举

public enum EnumB implements MyInterface {
    ;

    private MyInterface impl = new MyInterfaceImpl();

    public void someMethod() {
        impl.someMethod();
    }

}

Please do note that EnumAand EnumBare not really code duplication, since that is plain delegation (valid, in my opinion). Also please note that everything is nicely glued together by using interface.

请大家注意,EnumAEnumB不是真正的重复代码,因为这是普通的委托(有效的,在我看来)。另请注意,所有内容都通过使用界面很好地粘合在一起。

回答by missingfaktor

Here is how you can solve your problem with composition and delegation. (I think this is the DRYest you can get with Java, for the case in hand.)

以下是解决组合和委托问题的方法。(对于手头的案例,我认为这是您可以使用 Java 获得的DRYest。)

import java.util.*;

interface HasName {
  public String getName();
}

class EnumEnhancer<E extends Enum<E> & HasName> {
  private Map<String, E> lookup;

  public EnumEnhancer(E... values) {
    lookup = new HashMap<String, E>();
    for (E e : values) {
      lookup.put(e.getName(), e);
    }
  }

  public E lookup(String name) {
    return lookup.get(name);
  }

  public String toString(E e) {
    return e.getName();
  }
}

enum Color implements HasName { // This is interface inheritance.
  RED("red"), GREEN("green"), BLUE("blue");

  // This is composition. 
  private static final EnumEnhancer<Color> enhancer = 
    new EnumEnhancer<Color>(values());

  private String name;

  private Color(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  // This is delegation.
  public String toString() {
    return enhancer.toString(this);
  }

  // This too is delegation.     
  public static Color lookup(String name) {
    return enhancer.lookup(name);
  }
}

class Main {
  public static void main(String[] args) {
    System.out.println(Color.lookup("blue")); // prints blue
  }
}

回答by doublep

You can achieve this with Java 8 default interface methods:

您可以使用 Java 8 默认接口方法实现此目的:

public class test
{
    public static void main (String[] arguments) throws Exception
    {
        X.A.foo ();
        Y.B.foo ();
    }
}

interface MyEnumInterface
{
    String getCommonMessage ();
    String name ();

    default void foo ()
    {
        System.out.println (getCommonMessage () + ", named " + name ());
    }
}

enum X implements MyEnumInterface
{
    A, B;

    @Override
    public String getCommonMessage ()
    {
        return "I'm an X";
    }
}

enum Y implements MyEnumInterface
{
    A, B;

    @Override
    public String getCommonMessage ()
    {
        return "I'm an Y";
    }
}

Note that the interface doesn't know it will be implemented by enums, so it cannot use Enummethods on thisin the default methods. However, you may include those methods in the interface itself (like I did with name()) and then use them normally. They will be "implemented" for you by Enumwhen you declare an enumeration.

请注意,接口不知道它会通过枚举来实现的,所以它不能使用Enum的方法this在默认的方法。但是,您可以在接口本身中包含这些方法(就像我对 所做的那样name()),然后正常使用它们。Enum当您声明枚举时,它们将为您“实现” 。

回答by Jeremy

How about a static helper class that holds your common functions, call them from your enum methods.

一个包含常用函数的静态辅助类怎么样,从你的枚举方法中调用它们。

In regards to your comment about toString().

关于您对 toString() 的评论。

public enum MyEnum{

ONE("one");

public MyEnum(String m_Name){
  this.m_Name = m_Name;
}
public String toString(){
  return m_Name;
}
String m_Name;
}

回答by igreenfield

just define your common behviur in the First class:

只需在 First 类中定义您的常见行为:

public class First {
 public String name() {
  return "my name";
 }
 ...
}

and than extend it in each class:

然后在每个类中扩展它:

public SecondClass extends First {
 ...
}