13

私はそのようないくつかの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;
    }
}

ご覧のとおり、ここにはかなりのコード重複があります。抽象共通祖先クラスのようなものを紹介する方法があればいいのにと思います。しかし、Java列挙型は固有のものではありません。最善のアプローチは何でしょうか?ありがとう。


編集:Ł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 );
    }

}

いくつかの理由がわかります。しかし、それでもまだ満足のいくものではありません。

  1. lookup(String)リターンタイプが異なるため、インターフェイスを定義するのは困難です
  2. lookup(String)これは実際には重複ではなく仕様であることは理解できますが、m_NameフィールドとtoString()ロジックは少し冗長だと感じています。私たちは実際に列挙型の1つのカテゴリを指定しており、それは私の意見では「is-a」関係のようです。
4

5 に答える 5

18

インターフェイスのために、継承やプログラミングよりも構成を優先します。列挙型はクラス (通常ではありませんが、それでもクラス) であるため、共有ロジックを含むフィールドを作成できます。列挙型にインターフェイスを実装させ、実装をこのフィールドに委譲します。

関連するコード スニペット:

共有インターフェース

public interface MyInterface {

    void someMethod();

}

ロジックの実装

public class MyInterfaceImpl implements MyInterface {

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

}

最初の列挙

public enum EnumA implements MyInterface {
    ;

    private MyInterface impl = new MyInterfaceImpl();

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

}

2 番目の列挙型

public enum EnumB implements MyInterface {
    ;

    private MyInterface impl = new MyInterfaceImpl();

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

}

EnumAEnumBは実際にはコードの重複ではないことに注意してください。これは単純な委任であるためです (私の意見では有効です)。また、インターフェイスを使用することで、すべてがうまく結合されていることに注意してください。

于 2012-06-22T21:06:36.647 に答える
6

構成と委任に関する問題を解決する方法を次に示します。(私は、これがJava で得られるDRY est だと思います。)

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
  }
}
于 2012-06-22T21:24:23.963 に答える
6

これは、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";
    }
}

インターフェイスは列挙型によって実装されることを認識しないため、デフォルト メソッドでEnumメソッドを使用できないことに注意してください。thisただし、これらのメソッドをインターフェイス自体に含めて (私が で行ったようにname())、通常どおり使用することもできます。Enumこれらは、列挙型を宣言するまでに「実装」されます。

于 2015-04-22T08:38:21.930 に答える
0

共通関数を保持する静的ヘルパークラスはどうですか。列挙型メソッドから呼び出します。

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;
}
于 2012-06-22T20:56:17.180 に答える
-1

First クラスで共通の動作を定義するだけです。

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

各クラスでそれを拡張するよりも:

public SecondClass extends First {
 ...
}
于 2015-04-22T09:00:50.777 に答える