Схема DAO и принцип открытого закрывания
Я видел и работал с большим количеством более раннего кода DAO на основе JDBC, который обычно начинается с методов CRUD. Мой вопрос относится конкретно к методам поиска или "искателям". Обычно я нахожу, что DAO начинаются с двух методов:
- найти и вернуть ВСЕ
- получить конкретный экземпляр на основе уникального идентификатора
Чаще всего этих двух искателей недостаточно. Обычно я вижу, что класс DAO неоднократно модифицировался, чтобы добавить методы поиска, такие как:
- найти и вернуть ВСЕ, где {условие}
Что происходит, так это то, что добавляются новые методы при необходимости поддержки новых {условий} или существующих методов для добавления новых параметров в качестве флагов для изменения SQL-запроса внутри метода для поддержки дополнительных условий.
Это уродливый подход и нарушает принцип открытого закрытия. Я всегда видел, как классы DAO постоянно изменяются, когда требуется какое-то новое условие поиска. Исследование этого вопроса часто указывает мне на шаблон хранилища и инкапсулирует условия для поиска как Технические характеристики или объекты запроса, а затем передает их методу поиска. Но это кажется возможным только в том случае, если у вас есть сборка в памяти всего набора данных или если вы используете какой-то ORM (я работаю со старым кодом JDBC)
Я рассмотрел решение, которое ленивы загружает весь набор данных, который DAO управляет как коллекция в памяти, а затем использует шаблон спецификации в качестве запросов для извлечения. Затем я реализую своего рода наблюдателя в коллекции, который просто обновляет базу данных при создании, обновлении или удалении методов. Но, очевидно, производительность и масштабируемость значительно страдают.
Любые мысли об этом?
Спасибо за ответы. У меня есть одна мысль - каково ваше мнение об использовании шаблона Command/Policy для инкапсуляции запросов доступа к данным? Каждая отдельная команда Concrete может представлять определенный вид доступа и может быть передана Invoker. Я бы закончил с многочисленными классами Concrete Command, но каждый из них будет ориентирован только на один вид доступа и должен быть очень надежным и изолированным.
public abstract class Command<R>{
public <R> execute();
public void setArguments(CommandArguments args){
//store arguments
}
}
//map based structure for storing and returning arguments
public class CommandArguments{
public String getAsString(String key);
public String getAsInt(String key);
//... others
}
//In some business class...
Command command = CommandFactory.create("SearchByName");
CommandArguments args = new CommandArguments();
args.setValue("name", name);
// others
command.setArguments(args);
List<Customer> list = command.execute();
Ответы
Ответ 1
Мы использовали iBatis для нашего ORM слоя данных и смогли реализовать то, что вы предлагаете в одном запросе, передав объект параметра с различными полями, которые вы, возможно, захотите использовать в качестве параметров.
Затем в вашем предложении WHERE вы можете указать каждое поле как условие условия, но только если оно заселено в объекте параметра. Если только одно поле в параметре obj не равно null, то оно будет единственным, которое будет использоваться для фильтрации результатов.
Таким образом, если вам нужно добавить поля к вашим параметрам, вы просто измените SQL и paramObj. Затем у вас есть 2 метода, которые возвращают ВСЕ или подмножество на основе комбо переданных параметров, или, по крайней мере, этот подход уменьшит количество требуемых запросов.
например. что-то вроде...
SELECT * FROM MY_TABLE
WHERE FIELD_ZERO = paramObj.field0
<isNotNull property="paramObj.field1">AND FIELD_ONE = paramObj.field1</isNotNull>
<isNotNull property="paramObj.field2">AND FIELD_TWO = paramObj.field2</isNotNull>
<isNotNull property="paramObj.field3">AND FIELD_THREE = paramObj.field3</isNotNull>
Ответ 2
Вместо того, чтобы создавать конкретный метод поиска для каждого возможного условия по мере их появления, почему бы не создать общий API-интерфейс поиска?
Это может иметь форму DAO с внутренним Enum для представления полей и метод, который принимает список экземпляров внутреннего класса DAO с полями, представляющими, какое поле DAO фильтрует, какой фильтр применять к нему, и какое условие (И, ИЛИ и т.д.).
Это небольшая работа по настройке, и для небольших проектов может быть слишком много, но это, безусловно, возможно.
Структуры ORM обычно имеют нечто похожее, уже встроенное, поэтому вы можете подумать о принятии одного из них (или, по крайней мере, глядя на то, как они его реализовали при разработке собственного решения для переоснащения в ваше устаревшее приложение).