Как добавить общие методы для нескольких перечислений Java? (предки абстрактного класса?)
У меня есть несколько перечислений 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 );
}
}
Я вижу некоторые рассуждения. Однако это все еще не очень удовлетворительно.
- Трудно определить интерфейс для
lookup(String)
из-за другого типа возврата
- Я понимаю, что
lookup(String)
не является действительно дублированием, а спецификацией, но я все еще чувствую, что поле m_Name и логика toString() немного избыточны. Мы действительно указываем одну категорию перечисления, и, по моему мнению, это отношения "-a" .
Ответы
Ответ 1
Наслаждайтесь композицией по наследованию и программированием ради интерфейсов. Поскольку Enums являются классами (не регулярными, но все еще-классами), вы можете создать какое-либо поле, содержащее общую логику, позволить enum реализовать ваш интерфейс и делегировать реализацию в это поле.
Соответствующие фрагменты кода:
Общий интерфейс
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();
}
}
Второе перечисление
public enum EnumB implements MyInterface {
;
private MyInterface impl = new MyInterfaceImpl();
public void someMethod() {
impl.someMethod();
}
}
Обратите внимание, что EnumA
и EnumB
на самом деле не дублируют код, так как это простое делегирование (на мой взгляд). Также обратите внимание, что все красиво склеено с помощью интерфейса.
Ответ 2
Вот как вы можете решить свою проблему с композицией и делегированием. (Я думаю, что это DRY est вы можете получить с Java, для рассматриваемого случая.)
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
}
}
Ответ 3
Вы можете добиться этого с помощью методов интерфейса 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
, когда вы объявите перечисление.
Ответ 4
Как насчет статического вспомогательного класса, который содержит ваши общие функции, вызовите их из ваших методов enum.
Что касается вашего комментария о 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;
}
Ответ 5
просто определите общее поведение в первом классе:
public class First {
public String name() {
return "my name";
}
...
}
а затем расширьте его в каждом классе:
public SecondClass extends First {
...
}