Java - экземпляры реализации внутри интерфейса

В моем проекте мне нужно создавать объекты для каждого вида Java Math Operator, такие как "Добавить", "Подстановка", "Умножение" и т.д. И эти операторы должны быть одноточечными.

Итак, вот что я собираюсь делать. Я определяю Math Operator как интерфейс, и я помещаю эти реализации внутри него, поскольку я не хочу определять одноэлементные классы для каждого оператора.

public interface MathOperator {


double operate(double a, double b);

MathOperator ADD = new MathOperator(){

    @Override
    public double operate(double a, double b) {
        return a + b;
    }

};

MathOperator SUBSTRACT = new MathOperator(){

    @Override
    public double operate(double a, double b) {
        return a - b;
    }

};  

}

Я не вижу много такого использования, когда я это Google. Поэтому я задаюсь вопросом, является ли это хорошей практикой и есть ли более эффективные и более изящные подходы?

Ответ 1

Я бы сделал smt like

1) Определить интерфейс

interface MathOperator {
    double operate(double a, double b);
}

2) Чем некоторая общая реализация в перечислении (меньше кода)

enum MathOperators implements MathOperator {
    ADD {
        @Override
        public double operate(double a, double b) {
            return a + b;
        }
    },

    SUBTRACT {
        @Override
        public double operate(double a, double b) {
            return a - b;
        }
    }
}

3) Или публичные статические члены (более чистое решение).

class MathOperators {
    public static MathOperator ADD = new MathOperator() {
        @Override
        public double operate(double a, double b) {
            return a + b;
        }
    };
    public static MathOperator SUBTRACT = new MathOperator() {
        @Override
        public double operate(double a, double b) {
            return a - b;
        }
    };
}
  • может создать новый MathOperator без изменения MathOperators
  • иметь хороший API для общих операций
  • не следует писать синглтоны
  • иметь хороший чистый интерфейс

Ответ 2

Одна идиома, которую я видел в этих обстоятельствах, - это использование enum:

public enum MathOperator {

    ADD {
        @Override
        public double operate(double a, double b) {
            return a + b;
        }
    },

    SUBTRACT {
        @Override
        public double operate(double a, double b) {
            return a - b;
        }
    };

    public abstract double operate(double a, double b);

}

Ответ 3

Я часто использую этот шаблон, особенно для конкретных реализаций общих интерфейсов. Я нахожу, что это работает очень хорошо для меня.

Мне нравится, как он помещает реализации, где вы можете их найти. Я делаю это несколько иначе - я делаю их статичными (это стиль, поэтому интерфейс impls больше похож на класс impls):

public interface MathOperator {

    double operate(double a, double b);

    public static MathOperator ADD = new MathOperator() {
        @Override
        public double operate(double a, double b) {
            return a + b;
        }
    };

    public static MathOperator SUBSTRACT = new MathOperator() {
        @Override
        public double operate(double a, double b) {
            return a - b;
        }
    };

}

Ответ 4

Я не вижу никаких проблем с этим. Возьмите java.lang.String.CASE_INSENSITIVE_ORDER, например. Это почти то же самое, за исключением того, что

  • Строка не является интерфейсом, а конечным классом
  • Comparator не объявляется с использованием анонимного класса, но использует статический внутренний класс, который по сути является тем же самым

Ответ 5

Лично мне не нравится помещать реализации в интерфейсы. Я бы либо:

  • make MathOperator a enum
  • сохранить интерфейс, но factory или статический класс (скажем MathOperators) с реализациями

Ответ 6

Почему вы не определяете каждую реализацию в своем собственном классе/файле? Это сделает его более понятным и оставит интерфейс чистым.