2012-01-10 2 views
5

자바 열거 형을 다룰 때 코드 재사용을위한 최적의 디자인 패턴에 관한 질문이 있습니다. 기본적으로 정적 비즈니스 컬렉션 (상수 집합)을 모델링하는 여러 열거 형을 정의 할 수 있지만 가능한 최소한의 코딩으로 동작을 공유하고 싶습니다.자바 열거 형 확장하기

추상 클래스의 클래스 상속을 사용하면이 작업을 쉽게 수행 할 수 있지만 Java enum을 확장 할 수 없으므로 (인터페이스 만 구현할 수 있기 때문에) 이러한 유형의 작업은 지루하고 많은 오류가 발생하기 쉬운 복사/붙여 넣기 작업 (복사 enum에서 enum까지의 코드). 모든 열거 형 사이에서 공유되어야하는 "비즈니스 논리"의 예에는 문자열 변환, 인스턴스 및 논리 비교 등이 포함됩니다.

지금 가장 좋은 방법은 비즈니스 인터페이스와 함께 도우미 클래스를 사용하는 것입니다. 지금까지 코드 복잡성을 줄였습니다 (모든 열거 형은 여전히 ​​도우미 클래스를 선언하고 호출해야하므로). 예제를 참조하십시오 (명확히하기 위해) :

public enum MyEnum { 
    A, B, C; 

    // Just about any method fits the description - equals() is a mere example 
    public boolean equals(MyEnum that) { 
     ObjectUtils.equals(this, that); 
    } 
} 

StackOverflowers는이 "언어 기능"을 어떻게 처리합니까?

+0

과'Delegate' @, 내가 적이없는 롬복을 시도 할 수 enum으로 시도했습니다. –

+0

Java 6에서 열거 형은 최종 클래스입니다. 너는 그들을 확장 할 수 없다. 나는 자바 7이 동일하다고 믿는다. – DwB

+1

열거 형 (enum)이 만들어지지 않았습니다. 클래스 (열거 형 클래스)를 사용하거나 논리를 분리합니다. 당신은이 경우에 대한 팩토리 패턴을 사용할 수있다 (만약 행동이 enum에서 enum까지 충분히 다른 경우). – Viruzzo

답변

2

동일한 작업을 수행하거나 열거 형을 최고 열거 형으로 결합합니다.

Java 8을 사용하면 더 쉬울 것입니다. 인터페이스 메소드에 default 구현을 정의하고 enum 인터페이스를 확장 할 수 있습니다.

+0

'enum'을 슈퍼 -'''enum'으로 결합하는 것은 무엇을 의미합니까? 가치 A와 B가 의미가 없더라도 비교 될 수 있으므로 안전하지 않습니까? – lsoliveira

+0

안전하지 않을 수도 있으며, 상황에 따라 다릅니다. –

+0

결국 모든 다른 솔루션은 DRY 원칙을 위반하지 않으면 서 더 많은 복잡성을 추가합니다. 따라서 이것이 해결책 인 것 같습니다. 내 손가락을 넘기면 언젠가 Java에 확장 클래스가 생깁니다 ... – lsoliveira

2

유한 상태를 나타내는 경우를 제외하고는 거의 동작이 필요하지 않은 경우를 제외하고는 거의 enums입니다.

enums이 동작을 필요로하는 classesFactory으로 리팩터링 할 것을 제안합니다.

+0

enum은 값을 전달하기 위해 상수를 사용하는 것보다 훨씬 안전하며 조작하기에 훨씬 좋습니다 (EnumSet <...>,'switch' 등). 나는 그들이 C#보다 훨씬 강력하다는 데는 동의하지만, 여전히 자신의 위치를 ​​가지고있다. (특히 코드를 리펙토링하고 완전한 재 작성을 할 수 없을 때 특히 그렇다. :)). – lsoliveira

+0

나는'enums'가 오래된'final static int CONSTANT = 1'보다 낫다는 것에 동의하고 구문적인 설탕은 훌륭하지만,'enum'에 동작을 넣을 때마다 나는 그것을 후회합니다. –

+0

@Isoliveira Wait ** 덜 ** int보다 근본적으로 통사론적인 설탕 인 C# enum보다 강력합니까? 어떻게 결론에 도달 했습니까? 어쨌든 저는 Garett에 어느 정도 동의합니다 : 열거 형은 유한 상태를 나타 내기 위해 거기에 있습니다. 그럴 경우 어떻게 확장해야하는지 확실하지 않습니다. 그러나 열거 형에 간단한 (!) 상태를 갖는 것이 종종 유용합니다. 사소한 방법 이상이라면 클래스가되어야합니다. 예 : 내 getComplement() 메소드는 내 책에서 잘 될 것이다. – Voo

3

재사용 가능한 논리를 전용 (비 enum) 클래스로 이동 한 다음 열거 형을 해당 클래스에 위임 할 수 있습니다. 예를 들면 다음과 같습니다.

[참고 : PlusTwo extends PlusOne의 상속은 권장되지 않습니다 (b/c PlusTwo는 PlusOne이 아닙니다). 그것은 여기에 단지

public interface Logic { 
    public int calc(int n); 
} 

public static class PlusOne implements Logic { 
    public int calc(int n) { return n + 1; } 
} 

public static class PlusTwo extends PlusOne { 
    @Override 
    public int calc(int n) { return super.calc(n) + 1; } 
} 

public static enum X { 
    X1, X2; 
    public Logic logic; 

    public int doSomething() { 
    return logic.calc(10); 
    } 
} 

public static enum Y { 
    Y1, Y2; 
    public Logic logic; 

    public String doSomethingElse() { 
    return "Your result is '" + logic.calc(10) + "'"; 
    } 
} 

public static void main(String[] args) { 
    // One time setup of your logic: 
    X.X1.logic = new PlusOne(); 
    X.X2.logic = new PlusTwo(); 
    Y.Y1.logic = new PlusOne(); 
    Y.Y2.logic = new PlusTwo(); 

    System.out.println(X.X1.doSomething()); 
    System.out.println(X.X2.doSomething()); 
    System.out.println(Y.Y1.doSomethingElse()); 
    System.out.println(Y.Y2.doSomethingElse()); 
} 
+0

결국, 그것은 초기 제안서의 변형 일뿐입니다. 그것은 단지 구현 로직을 분리시킨다. 나는 또한'Logic'을위한 팩토리를 사용할 것이고, 그렇게 노출시키지 않을 것입니다. (당신도 그렇게 할 것입니다. – lsoliveira

0

이 조금 추한 보일 수 있습니다]. 기존의 논리를 확장 할 수 있다는 점을 설명하기 위해, 그러나 일반적으로 당신에게 필요한 기능을 제공 할 수 있습니다.

당신은 인터페이스

public interface MyEnumInterface<T extends Enum<T>> { 

    String getBusinessName(); 

    T getEnum(); 

} 

구현

public enum OneOfMyEnums implements MyEnumInterface<OneOfMyEnums>{ 

    X, Y, Z; 

    @Override 
    public String getBusinessName() { 
     return "[OneOfMyEnums]" + name(); 
    } 

    @Override 
    public OneOfMyEnums getEnum() { 
     return this; 
    } 

} 

그리고 유틸리티 클래스 대신에 당신의 부모 클래스를 가질 수 있습니다

public class MyEnumUtils { 

    public static <T extends Enum<T>> String doSomething(MyEnumInterface<T> e){ 
     e.getBusinessName(); // can use MyEnumInterface methods 
     e.getEnum().name(); // can use Enum methods as well 
     return null; 
    } 

} 
+0

이 접근법은 흥미 롭지 만 클라이언트가'enum' 대신 유틸리티 클래스에 의존하게함으로써 계약을 뒤집습니다 ('equals()'메소드는'MyEnumUtils'로 들어갑니다). – lsoliveira