Шаблон проектирования для настраиваемой системы

У меня есть интересная проблема дизайна, которую я попытаюсь упростить в игрушечной проблеме ниже:

Я хочу создать систему, для которой вывод будет студенческим объектом на основе определенных входных данных и промежуточной обработки. Поток будет следующим: у меня есть список классных комнат как один тип ввода. Чтобы сгенерировать выход, этапы обработки:

  • Отфильтруйте каждый класс учеников в возрасте до X (скажем, 10)
  • Сортировка отфильтрованных результатов с помощью любой перестановки этого иерархического порядка: высота, вес, длина руки
  • Верните 8 лучших учеников.

Другой вход может быть просто списком учеников, которые у меня уже есть, и хочу включить их в качестве части результата. Например: вход 1: список из 3 студентов, вход 2: список из 2 классных комнат, для которых будут выполняться этапы обработки выше.

Каким будет наилучший способ разработки такой системы с входными данными:

  • тип ввода {student list|classroom list},
  • тип фильтра {age|height|etc},
  • порядок сортировки {any ordering of height,weight,arm length},
  • returnNum {how many students to return}

Система должна быть достаточно гибкой, чтобы учесть больше типов ввода и больше записей порядка сортировки (т.е. сортировать учащихся по размеру обуви}. Какую структуру данных я могу использовать для моделирования каждой части этого раздела (то есть, каков наилучший способ представления критериев порядка сортировки?) Существует ли какой-либо шаблон проектирования, который бы соответствовал этим потребностям? Любая помощь в проектировании архитектуры будет с благодарностью!

Ответы

Ответ 1

Ну, то, что вы предлагаете, можно легко сделать с потоками Java 8, поэтому я предполагаю, что один шаблон, который вы можете использовать, - это pipeline. Вы также можете реализовать это с помощью внутренних итераторов :

List<Student> found = Stream.of(student1, student2, student3, ..., studentn)
    .filter(s -> s.getAge() > 100)
    .sorted(Comparator.comparing(Student::getHeight).thenComparing(Student::getWeight))
    .limit(10)
    .collect(Collectors.toList());

Ответ 2

Из требований, хотя оба Student и Classroom равны StudentSource s, фильтрация и сортировка всегда действуют на Student (они никогда не фильтруются или не сортируются по классу в ваших вводах образцов). Фильтрация довольно проста:

// interface with a single method, reduces to a lambda too
interface Filter<T> {
    boolean accept(T candidate);
}

Сортировка канонически:

package java.util;
// interface with a single method, reduces to a lambda too
interface Comparable<T> {
    int compareTo(T a, T b);
}

Оба вышеперечисленных являются приложениями шаблона проектирования Visitor. Как и с кратким ответом от @Edwin, вы выстраиваете своих посетителей в конвейер (фаза конфигурации), а затем нажимаете на них (этап выполнения). Обратите внимание, что шаблон посетителя имеет "причины", которые um, ученики должны читать в своей книге "Банда 4".

Вы ничего не говорите:

  • как входы представлены в программу (например, в виде текста, который необходимо разобрать)
  • Возможно ли, что один и тот же ученик может появиться в более чем 1 классе или список учеников... это имеет отношение к тому, какая коллекция Java вы можете передать Comparator to;

Итак, задача под рукой сводится к:

  • прочитайте определения фильтров, сортировщиков, ограничителей, создайте посетителей для этих
  • прочитайте данные (классные комнаты/ученики), и для каждого найденного студента сделайте if passesAllFilters(student) okstudents.add(student);, где okstudents является java.util.TreeSet, загрунтованным с помощью Comparator, остановитесь, когда достигнут предел.

Вы могли бы подсказать, что шаг, который принимает "ввод, который определяет фильтр (ы)", является "factory методом", но это действительно не помогает.. List<Filter<Student>> getFilters(String filterSpec) действительно не приведет вас нигде, где factory полезен. Разбор фильтров и появление кода, который ссылается на конкретные свойства учащихся, применяет выражения и т.д., Не может быть тривиальной задачей. В зависимости от типов выражений, которые необходимы ваши фильтры, вы можете захотеть заглянуть в генератор компилятора, такой как ANTLR 4. Вам, вероятно, придется использовать отражение.

Ответ 3

взгляните на https://docs.oracle.com/javase/7/docs/api/java/util/SortedMap.html

вы можете использовать несколько SortedMap (по одному для каждого ключа), в которые вы помещаете каждый элемент вашего списка с соответствующим ключом для каждой карты (es: sortedMapAge.put(carl, 18)..sortedMapHeight(carl, "1.75" )...).

поэтому с помощью итератора вы можете получить доступ к своим членам списка с помощью ключей varius с помощью соответствующей SortedMap.

И если вы хотите сохранить alla, что карты на другом уровне абстракции, вы можете сохранить их в hashmap и использовать в качестве ключа идентификатор ключа (sortedMapAge... key Age, sortedMapHeight height....)

Это довольно сложно, но карты предлагают вам хорошие способы организации объектов с помощью набора ключей.

Ответ 4

Лично я сделал бы это так:

public <E> List<E> query(List<E> dataset, Filter<E> filter, Comparator<E> sortOrder, int maxResults);

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