Enum이 인터페이스를 구현하는 이유는 무엇입니까?


답변:


130

열거 형은 패시브 세트 (예 : 색상)를 나타내지 않아도됩니다. 그들은 기능을 더 복잡한 객체를 나타낼 수 있습니다, 그래서 당신은 가능성이에 더 기능을 추가 할 수있는 좋은 방법입니다 - 당신과 같은 인터페이스 할 수 있습니다 예 Printable, Reportable이들을 지원 등 및 구성 요소를.


259

다음은 한 가지 예입니다 (유효한 Java 2nd Edition에있는 유사 / 더 나은 예).

public interface Operator {
    int apply (int a, int b);
}

public enum SimpleOperators implements Operator {
    PLUS { 
        int apply(int a, int b) { return a + b; }
    },
    MINUS { 
        int apply(int a, int b) { return a - b; }
    };
}

public enum ComplexOperators implements Operator {
    // can't think of an example right now :-/
}

이제 Simple + Complex 연산자의 목록을 얻으려면 다음을 수행하십시오.

List<Operator> operators = new ArrayList<Operator>();

operators.addAll(Arrays.asList(SimpleOperators.values()));
operators.addAll(Arrays.asList(ComplexOperators.values()));

따라서 인터페이스를 사용하여 확장 가능한 열거 형을 시뮬레이션합니다 (인터페이스를 사용하지 않으면 불가능합니다).


3
복잡한 연산자는 "pow"등일 수 있습니다.
Pimgd

2
Enum 구문 (멤버 뒤에 중괄호가 있음)을 처음 보았을 때 6 년 동안 Java로 프로그래밍 해 왔습니다. 틸.
jrahhali

23

Comparable여러 사람에 의해 주어진 예제는 여기에 있기 때문에, 잘못 Enum이미 구현이. 당신은 그것을 무시할 수 없습니다.

더 좋은 예는 데이터 유형을 정의하는 인터페이스를 갖는 것입니다. 간단한 유형을 구현하는 열거 형을 가질 수 있고 복잡한 유형을 구현하는 일반 클래스를 가질 수 있습니다.

interface DataType {
  // methods here
}

enum SimpleDataType implements DataType {
  INTEGER, STRING;

  // implement methods
}

class IdentifierDataType implements DataType {
  // implement interface and maybe add more specific methods
}

2
예. !! Enum은 이미 Comparable 인터페이스를 구현하고 재정의를 허용하지 않습니다. enum 클래스에 대한 Java 소스 코드를 조회하고 compareTo 구현을 찾을 수 없습니다. 누구든지 compareTo 메소드 내에서 ENUM이 비교되는 것을 말해 줄 수 있습니까?
Akh

2
@AKh 순서를 비교합니다. 즉, 자연 순서는 열거 상수가 소스 파일에있는 순서입니다.
Jorn

열거 형 변수는 최종이므로 ==으로 비교가 발생합니까?
djangofan

@djangofan 예.
Jorn February

18

내가 자주 사용하는 경우가 있습니다. IdUtil매우 간단한 Identifiable인터페이스를 구현하는 객체로 작업하는 정적 메서드 가있는 클래스가 있습니다.

public interface Identifiable<K> {
    K getId();
}


public abstract class IdUtil {

    public static <T extends Enum<T> & Identifiable<S>, S> T get(Class<T> type, S id) {
        for (T t : type.getEnumConstants()) {
            if (Util.equals(t.getId(), id)) {
                return t;
            }
        }
        return null;
    }

    public static <T extends Enum<T> & Identifiable<S>, S extends Comparable<? super S>> List<T> getLower(T en) {
        List<T> list = new ArrayList<>();
        for (T t : en.getDeclaringClass().getEnumConstants()) {
             if (t.getId().compareTo(en.getId()) < 0) {
                 list.add(t);
            }
        }
        return list;
    }
}

내가 만들면 Identifiable enum:

    public enum MyEnum implements Identifiable<Integer> {

        FIRST(1), SECOND(2);

        private int id;

        private MyEnum(int id) {
            this.id = id;
        }

        public Integer getId() {
            return id;
        }

    }

그런 다음 id이 방법으로 얻을 수 있습니다 .

MyEnum e = IdUtil.get(MyEnum.class, 1);

정확히 내가 필요한 것!
페트로 넬라

13

Enum은 인터페이스를 구현할 수 있으므로 싱글 톤 패턴을 엄격히 적용하는 데 사용할 수 있습니다. 싱글 톤으로 표준 클래스를 만들려고하면 ...

  • 리플렉션 기법을 사용하여 개인 메서드를 공개로 노출 할 수있는 가능성
  • 싱글 톤에서 상속하고 싱글 톤의 메소드를 다른 것으로 재정의

싱글 톤으로서 열거 형은 이러한 보안 문제를 방지하는 데 도움이됩니다. 이것은 Enum이 클래스로 작동하고 인터페이스를 구현하게하는 주된 이유 중 하나 일 수 있습니다. 그냥 추측.

자세한 내용은 /programming/427902/java-enum-singletonJava의 싱글 톤 클래스를 참조 하십시오 .


1
for inheriting from your singleton and overriding your singleton's methods with something else. 당신은 그것을 final class막기 위해 그냥 사용할 수 있습니다
Dylanthepiguy

10

확장 성이 필요합니다. 누군가 개발 한 API를 사용하는 경우 정의한 열거 형은 정적입니다. 추가하거나 수정할 수 없습니다. 그러나 인터페이스를 구현하게하면 API를 사용하는 사람이 동일한 인터페이스를 사용하여 자체 열거 형을 개발할 수 있습니다. 그런 다음이 열거 형을 열거 형 관리자에 등록하여 표준 인터페이스와 함께 열거 형을 집약합니다.

편집 : @Helper Method에는 완벽한 예가 있습니다. 다른 라이브러리가 새로운 연산자를 정의하고 관리자 클래스에 '이 열거 형이 존재합니다-등록하십시오'라고 알려주십시오. 그렇지 않으면 자신의 코드에서만 연산자를 정의 할 수 있습니다. 확장 성이 없습니다.


7

열거 형은 변장 된 클래스 일 뿐이므로 대부분 열거 형으로 수행 할 수있는 클래스로 수행 할 수있는 모든 작업입니다.

열거 형이 인터페이스를 구현할 수 없어야하는 이유를 생각할 수 없으며 동시에 그들에게도 좋은 이유를 생각할 수 없습니다.

인터페이스 또는 메소드와 같은 것을 열거 형에 추가하기 시작하면 실제로 클래스로 만드는 것을 고려해야합니다. 물론 나는 비 전통적인 열거 형 일을하는 데 유효한 사례가 있다고 확신하며, 그 한계는 인공적인 것이기 때문에 사람들이 원하는 것을 할 수있게하는 것을 선호합니다.


4
"... 그래서 당신이 열거 형으로 할 수있는 클래스로 할 수있는 대부분의 일에 대해"그러나 나는 열거 형이 추상 클래스에서 상속 받았다고 말할 수 없습니다. 예, "대부분"을 강조합니다.
Adam Parkin

5
열거 형은 모두 java.lang.Enum을 확장하고 Java 클래스는 하나의 클래스에서만 확장 할 수 있기 때문입니다.
TofuBeer

6

예를 들어 로거 열거 형이있는 경우 그런 다음 인터페이스에 디버그, 정보, 경고 및 오류와 같은 로거 메소드가 있어야합니다. 코드가 느슨하게 결합됩니다.


6

이것에 대한 가장 일반적인 사용법은 두 열거 형의 값을 하나의 그룹으로 병합하고 유사하게 취급하는 것입니다. 예를 들어 Fruits and Vegatables 가입 방법을 참조하십시오 .


5

인터페이스와 함께 enum을 사용하는 가장 좋은 사용 사례 중 하나는 Predicate 필터입니다. 아파치 컬렉션의 타이핑 부족을 해결하는 매우 우아한 방법입니다 (다른 라이브러리를 사용할 수없는 경우).

import java.util.ArrayList;
import java.util.Collection;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;


public class Test {
    public final static String DEFAULT_COMPONENT = "Default";

    enum FilterTest implements Predicate {
        Active(false) {
            @Override
            boolean eval(Test test) {
                return test.active;
            }
        },
        DefaultComponent(true) {
            @Override
            boolean eval(Test test) {
                return DEFAULT_COMPONENT.equals(test.component);
            }
        }

        ;

        private boolean defaultValue;

        private FilterTest(boolean defautValue) {
            this.defaultValue = defautValue;
        }

        abstract boolean eval(Test test);

        public boolean evaluate(Object o) {
            if (o instanceof Test) {
                return eval((Test)o);
            }
            return defaultValue;
        }

    }

    private boolean active = true;
    private String component = DEFAULT_COMPONENT;

    public static void main(String[] args) {
        Collection<Test> tests = new ArrayList<Test>();
        tests.add(new Test());

        CollectionUtils.filter(tests, FilterTest.Active);
    }
}

5

위에서 언급 한 전략에 대한 게시물은 열거 형을 사용하여 전략 패턴을 훌륭하게 구현하여 얻는 이점을 충분히 강조하지 못했습니다.

public enum Strategy {

  A {
    @Override
    void execute() {
      System.out.print("Executing strategy A");
    }
  },

  B {
    @Override
    void execute() {
      System.out.print("Executing strategy B");
    }
  };

  abstract void execute();
}

각각에 대해 별도의 컴파일 단위가 없어도 한 곳에서 모든 전략을 가질 수 있습니다. 다음과 같이 멋진 동적 디스패치를 ​​얻습니다.

Strategy.valueOf("A").execute();

Java를 거의 느슨하게 입력 한 언어처럼 읽습니다!


3

열거 형은 Java 클래스와 유사하며 생성자, 메소드 등을 가질 수 있습니다. 이것으로 할 수없는 유일한 것은입니다 new EnumName(). 인스턴스는 열거 형 선언에 미리 정의되어 있습니다.


무엇에 대해 enum Foo extends SomeOtherClass? 따라서 정규 수업과 같은 것은 실제로는 다릅니다.
Adam Parkin

@ 아담 : 나는 열거 형이 클래스와 닮은 방식이 클래스와 다른 방식보다 훨씬 많다고 말하고 싶습니다. 그러나 아닙니다. 동일하지 않습니다.
scottb

열거 형을 디 컴파일하면 열거 형을 확장하고 생성자 / 초기화 필드에서 이미 "상수 자"가 인스턴스화 된 클래스임을 알 수 있습니다.
Cosmin Cosmin

3

또 다른 가능성 :

public enum ConditionsToBeSatisfied implements Predicate<Number> {
    IS_NOT_NULL(Objects::nonNull, "Item is null"),
    IS_NOT_AN_INTEGER(item -> item instanceof Integer, "Item is not an integer"),
    IS_POSITIVE(item -> item instanceof Integer && (Integer) item > 0, "Item is negative");

    private final Predicate<Number> predicate;
    private final String notSatisfiedLogMessage;

    ConditionsToBeSatisfied(final Predicate<Number> predicate, final String notSatisfiedLogMessage) {
        this.predicate = predicate;
        this.notSatisfiedLogMessage = notSatisfiedLogMessage;
    }

    @Override
    public boolean test(final Number item) {
        final boolean isNotValid = predicate.negate().test(item);

        if (isNotValid) {
            log.warn("Invalid {}. Cause: {}", item, notSatisfiedLogMessage);
        }

        return predicate.test(item);
    }
}

그리고 사용 :

Predicate<Number> p = IS_NOT_NULL.and(IS_NOT_AN_INTEGER).and(IS_POSITIVE);

3

jar 파일에서 상수를 만들 때 사용자가 열거 형 값을 확장 할 수 있도록하는 것이 종종 도움이됩니다. 우리는 PropertyFile 키에 열거 형을 사용했으며 아무도 새로운 키를 추가 할 수 없기 때문에 막혔습니다! 아래는 훨씬 잘 작동했을 것입니다.

주어진:

public interface Color {
  String fetchName();
}

과:

public class MarkTest {

  public static void main(String[] args) {
    MarkTest.showColor(Colors.BLUE);
    MarkTest.showColor(MyColors.BROWN);
  }

  private static void showColor(Color c) {
    System.out.println(c.fetchName());
  }
}

하나는 항아리에 하나의 열거 형을 가질 수 있습니다.

public enum Colors implements Color {
  BLUE, RED, GREEN;
  @Override
  public String fetchName() {
    return this.name();
  }
}

사용자는 자신의 색상을 추가하기 위해 확장 할 수 있습니다.

public enum MyColors implements Color {
  BROWN, GREEN, YELLOW;
  @Override
  public String fetchName() {
    return this.name();
  }
}

2

여기 내 이유가 있습니다 ...

JavaFX ComboBox를 Enum 값으로 채웠습니다. 검색 할 목적으로 응용 프로그램에서 객체를 식별하는 방법을 지정할 수있는 Identifiable 인터페이스 (하나의 방법 지정 : 식별)가 있습니다. 이 인터페이스를 사용하면 ID 일치에 대한 모든 유형의 객체 (객체가 ID에 사용할 수있는 필드) 목록을 검색 할 수 있습니다.

ComboBox 목록에서 ID 값과 일치하는 항목을 찾고 싶습니다. Enum 값을 포함하는 ComboBox에서이 기능을 사용하려면 Enum에서 Identifiable 인터페이스를 구현할 수 있어야합니다 (Enum의 경우에는 구현하기가 쉽지 않습니다).


1

거기에서 인스턴스 제어를 유지하는 전략을 설명하는 인터페이스에서 내부 열거 형을 사용했습니다 (각 전략은 싱글 톤입니다).

public interface VectorizeStrategy {

    /**
     * Keep instance control from here.
     * 
     * Concrete classes constructors should be package private.
     */
    enum ConcreteStrategy implements VectorizeStrategy {
        DEFAULT (new VectorizeImpl());

        private final VectorizeStrategy INSTANCE;

        ConcreteStrategy(VectorizeStrategy concreteStrategy) {
            INSTANCE = concreteStrategy;
        }

        @Override
        public VectorImageGridIntersections processImage(MarvinImage img) {
            return INSTANCE.processImage(img);
        }
    }

    /**
     * Should perform edge Detection in order to have lines, that can be vectorized.
     * 
     * @param img An Image suitable for edge detection.
     * 
     * @return the VectorImageGridIntersections representing img's vectors 
     * intersections with the grids.
     */
    VectorImageGridIntersections processImage(MarvinImage img);
}

열거 형이 전략을 구현한다는 사실은 열거 형 클래스가 동봉 된 인스턴스의 프록시 역할을하도록 편리합니다. 또한 인터페이스를 구현합니다.

일종의 전략입니다 .EnumProxy : P clent 코드는 다음과 같습니다.

VectorizeStrategy.ConcreteStrategy.DEFAULT.processImage(img);

인터페이스를 구현하지 않은 경우 다음과 같습니다.

VectorizeStrategy.ConcreteStrategy.DEFAULT.getInstance().processImage(img);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.