답변:
다음은 한 가지 예입니다 (유효한 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()));
따라서 인터페이스를 사용하여 확장 가능한 열거 형을 시뮬레이션합니다 (인터페이스를 사용하지 않으면 불가능합니다).
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
}
내가 자주 사용하는 경우가 있습니다. 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);
Enum은 인터페이스를 구현할 수 있으므로 싱글 톤 패턴을 엄격히 적용하는 데 사용할 수 있습니다. 싱글 톤으로 표준 클래스를 만들려고하면 ...
싱글 톤으로서 열거 형은 이러한 보안 문제를 방지하는 데 도움이됩니다. 이것은 Enum이 클래스로 작동하고 인터페이스를 구현하게하는 주된 이유 중 하나 일 수 있습니다. 그냥 추측.
자세한 내용은 /programming/427902/java-enum-singleton 및 Java의 싱글 톤 클래스를 참조 하십시오 .
for inheriting from your singleton and overriding your singleton's methods with something else
. 당신은 그것을 final class
막기 위해 그냥 사용할 수 있습니다
확장 성이 필요합니다. 누군가 개발 한 API를 사용하는 경우 정의한 열거 형은 정적입니다. 추가하거나 수정할 수 없습니다. 그러나 인터페이스를 구현하게하면 API를 사용하는 사람이 동일한 인터페이스를 사용하여 자체 열거 형을 개발할 수 있습니다. 그런 다음이 열거 형을 열거 형 관리자에 등록하여 표준 인터페이스와 함께 열거 형을 집약합니다.
편집 : @Helper Method에는 완벽한 예가 있습니다. 다른 라이브러리가 새로운 연산자를 정의하고 관리자 클래스에 '이 열거 형이 존재합니다-등록하십시오'라고 알려주십시오. 그렇지 않으면 자신의 코드에서만 연산자를 정의 할 수 있습니다. 확장 성이 없습니다.
열거 형은 변장 된 클래스 일 뿐이므로 대부분 열거 형으로 수행 할 수있는 클래스로 수행 할 수있는 모든 작업입니다.
열거 형이 인터페이스를 구현할 수 없어야하는 이유를 생각할 수 없으며 동시에 그들에게도 좋은 이유를 생각할 수 없습니다.
인터페이스 또는 메소드와 같은 것을 열거 형에 추가하기 시작하면 실제로 클래스로 만드는 것을 고려해야합니다. 물론 나는 비 전통적인 열거 형 일을하는 데 유효한 사례가 있다고 확신하며, 그 한계는 인공적인 것이기 때문에 사람들이 원하는 것을 할 수있게하는 것을 선호합니다.
이것에 대한 가장 일반적인 사용법은 두 열거 형의 값을 하나의 그룹으로 병합하고 유사하게 취급하는 것입니다. 예를 들어 Fruits and Vegatables 가입 방법을 참조하십시오 .
인터페이스와 함께 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);
}
}
위에서 언급 한 전략에 대한 게시물은 열거 형을 사용하여 전략 패턴을 훌륭하게 구현하여 얻는 이점을 충분히 강조하지 못했습니다.
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를 거의 느슨하게 입력 한 언어처럼 읽습니다!
열거 형은 Java 클래스와 유사하며 생성자, 메소드 등을 가질 수 있습니다. 이것으로 할 수없는 유일한 것은입니다 new EnumName()
. 인스턴스는 열거 형 선언에 미리 정의되어 있습니다.
enum Foo extends SomeOtherClass
? 따라서 정규 수업과 같은 것은 실제로는 다릅니다.
또 다른 가능성 :
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);
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();
}
}
여기 내 이유가 있습니다 ...
JavaFX ComboBox를 Enum 값으로 채웠습니다. 검색 할 목적으로 응용 프로그램에서 객체를 식별하는 방법을 지정할 수있는 Identifiable 인터페이스 (하나의 방법 지정 : 식별)가 있습니다. 이 인터페이스를 사용하면 ID 일치에 대한 모든 유형의 객체 (객체가 ID에 사용할 수있는 필드) 목록을 검색 할 수 있습니다.
ComboBox 목록에서 ID 값과 일치하는 항목을 찾고 싶습니다. Enum 값을 포함하는 ComboBox에서이 기능을 사용하려면 Enum에서 Identifiable 인터페이스를 구현할 수 있어야합니다 (Enum의 경우에는 구현하기가 쉽지 않습니다).
거기에서 인스턴스 제어를 유지하는 전략을 설명하는 인터페이스에서 내부 열거 형을 사용했습니다 (각 전략은 싱글 톤입니다).
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);