Дизайн API: один общий интерфейс против трех специализированных интерфейсов? - PullRequest
0 голосов
/ 10 июля 2011

Я работаю над инструментом, где пользователи могут использовать свои собственные аннотации для описания рабочего процесса обработки данных (например, проверка, преобразование и т. Д.).

Помимо использования готовых к использованию аннотаций, пользователи могут создавать свои собственные: для этого им нужно объявить сам класс аннотаций, а затем реализовать процессор аннотаций (<- это главный вопрос этого вопроса). </p>

Сконфигурированный метод для обработки данных может выглядеть следующим образом:

void foo(@Provide("dataId") @Validate(Validator.class) String str) {    
   doSmth(str); 
}

Естественно, есть три группы аннотаций:

  1. те, которые производят начальные значения;
  2. те, которые преобразуют значения (преобразователи);
  3. те, которые просто читают значения и выполняют некоторую работу (валидаторы, разные потребители).

Поэтому мне нужно сделать выбор: либо создать один интерфейс для обработки всех этих типов аннотаций, которыйможет выглядеть так:

interface GenericAnnotationProcessor {    
    Object processAnnotation(Annotation annotation, Object processedValue);
}

Или я могу добавить 3 интерфейса к API:

interface ProducerAnnotationProcessor {     
    Object produceInitValue(Annotation annotation);
}

interface TransformerAnnotationProcessor {         
    Object transformValue(Annotation annotation, Object currentValue);
}

interface ConsumerAnnotationProcessor { 
    void consumeValue(Annotation annotation, Object currentValue);
}

Первый вариант не очень понятен для васДа, но третий вариант загрязняет API тремя почти схожими интерфейсами.

Что бы вы выбрали (прежде всего, как пользователь API) и почему?

Спасибо!

Ответы [ 3 ]

0 голосов
/ 10 июля 2011

Просто углубиться в вашу проблему.

Поскольку они выполняют аналогичные задачи, с некоторой дисперсией, Шаблон стратегии # Пример должен помочь вам.

Ваша проблема должна выглядеть примерно так:

interface GenericAnnotationProcessor {    
    Object processAnnotation(Annotation annotation, Object processedValue);
}

interface ProducerAnnotationProcessor implements GenericAnnotationProcessor {
}

interface TransformerAnnotationProcessor implements GenericAnnotationProcessor {
}

interface ConsumerAnnotationProcessor implements GenericAnnotationProcessor {
}

Теперь вы можете следовать примеру из Wiki

class Context {

    // map of annotation processors

    // register(add/remove) annotation processors to the map

    public int executeAnnotationProcessor(Annotation annotation, Object processedValue) {
        return locateAnnotationProcessor(annotation).processAnnotation(annotation, processedValue);
    }

    private GenericAnnotationProcessor locateAnnotationProcessor(Annotation annotation) {
        // return expected annotation processor
    }
}

Полагаю, вы понимаете.

0 голосов
/ 11 июля 2011

Вы можете использовать Интерфейсы, расширяющие интерфейсы Подробнее там

Подобно классам, вы можете создавать иерархии наследования интерфейсов, используя ключевое слово extends, например:

interface Washable {
    void wash();
}

interface Soakable extends Washable {
    void soak();
}

В этом примере интерфейс Soakable расширяет интерфейс Washable. Следовательно, Soakable наследует всех членов Washable. Класс, реализующий Soakable, должен предоставлять тела для всех методов, объявленных или унаследованных Soakable, wash () и soak (), или объявленных как абстрактные. Обратите внимание, что только интерфейсы могут «расширять» другие интерфейсы. Классы не могут расширять интерфейсы, они могут только реализовывать интерфейсы.

Надеюсь, это поможет.

0 голосов
/ 10 июля 2011

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

При использовании API я бы ожидал объявить переменную, которая реализует GenericAnnotationProcessor, а затем назначить соответствующий тип реализации в зависимости от моих потребностей.

Здесь, в Портленде, Орегон, рано, но в данный момент, при 50% необходимого мне уровня кофеина, мне кажется, что это обеспечит максимальную гибкость при максимальном повторном использовании кейда.

Конечно, ваши фактические условия могут продиктовать иначе.,.

Надеюсь, что это было полезно!

...