Шаблон проектирования для настраиваемой системы
У меня есть интересная проблема дизайна, которую я попытаюсь упростить в игрушечной проблеме ниже:
Я хочу создать систему, для которой вывод будет студенческим объектом на основе определенных входных данных и промежуточной обработки. Поток будет следующим: у меня есть список классных комнат как один тип ввода. Чтобы сгенерировать выход, этапы обработки:
- Отфильтруйте каждый класс учеников в возрасте до 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 для количества возвращаемых результатов.