Модель DAO и принцип Open-Closed - PullRequest
10 голосов
/ 17 февраля 2011

Я видел и работал со многими более старыми, основанными на JDBC кодами DAO, которые обычно начинаются с методов CRUD.Мой вопрос относится конкретно к поисковым методам, или «искателям».Обычно я обнаруживаю, что DAO начинаются с двух методов:

  • найти и вернуть ALL
  • для извлечения конкретного экземпляра на основе уникального идентификатора

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

  • найти и вернуть ВСЕ, где {условие}

Что происходит, когда больше методовдобавляются, когда необходимо поддерживать новые {условия} или когда существующие методы модифицируются для добавления новых параметров в качестве флагов для изменения SQL-запроса внутри метода для поддержки дополнительных условий.

Это уродливый подход и нарушаетОткрытый Закрытый Принцип.Я всегда был в восторге от того, что классы DAO постоянно модифицируются всякий раз, когда необходимо поддерживать какое-то новое условие поиска.Исследования по этому вопросу часто указывают на шаблон репозитория и инкапсулируют условия для извлечения в виде Спецификации или объектов Query, а затем передают их в метод поиска.Но это кажется возможным только в том случае, если у вас есть коллекция всего набора данных в памяти или если вы используете какой-то ORM (я работаю со старым кодом JDBC)

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

Есть мысли по этому поводу?


Спасибо за ответы до сих пор.У меня есть одна мысль - что вы думаете об использовании шаблона Command / Policy для инкапсуляции запросов на доступ к данным?Каждая отдельная конкретная команда может представлять определенный вид доступа и может быть передана в 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();

Ответы [ 2 ]

4 голосов
/ 18 февраля 2011

Мы использовали iBatis для нашего уровня данных ORM и смогли реализовать то, что вы предлагаете, в одном запросе, передав объект параметра с различными полями, которые вы, возможно, захотите использовать в качестве параметров.

Тогда в своем предложении WHERE вы можете указать каждое поле как условие, но только если оно заполнено в объекте параметра. Если только одно поле в параметре obj не равно нулю, оно будет единственным, которое будет использоваться для фильтрации результатов.

Таким образом, если вам нужно добавить поля к вашим параметрам, вы просто измените 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>
0 голосов
/ 17 февраля 2011

Вместо создания специального метода поиска для каждого возможного условия, когда они становятся очевидными, почему бы не создать универсальный API поиска? Это может принять форму DAO, имеющего внутренний Enum для представления полей, и метод, который принимает список экземпляров внутреннего класса DAO с полями, представляющими, какое поле DAO фильтровать, какой фильтр применять к нему, и какое условие (И, ИЛИ и т. д.).

Это небольшая работа по настройке, и для небольших проектов это может быть излишним, но это, безусловно, выполнимо. В каркасы ORM, как правило, уже встроено нечто подобное, поэтому вы можете подумать о принятии одного из них (или, по крайней мере, взглянуть на то, как они реализовали это при разработке собственного решения для встраивания в старое приложение).

...