Должен ли DAO быть синглтоном или нет?

14

Я разрабатываю RESTful API, и я думаю, что для моих ресурсов удобно использовать DAO, потому что, хотя я планирую просто использовать память для их хранения, я не хочу закрывать дверь тому, кто использует мою библиотеку, если они решили использовать реализация базы данных для DAO.

Мой вопрос заключается в том, должен ли DAO быть одиночным или нет. Если это не так, у службы будет экземпляр DAO, и он будет выглядеть примерно так:

@Path("eventscheduler")
public class EventSchedulerService {
    private IEventSchedulerDao dao = new EventSchedulerDao();

    // in case a different implementation is to be used
    public void setEventSchedulerDao(IEventSchedulerDao dao) {
        this.dao = dao;
    }

    @Path("{uniqueName}")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Tournament getTournament(@PathParam("name") String uniqueName) {
        return dao.get(uniqueName);
    }

    @Path("create")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Tournament createTournament(Tournament tournament) {
        return dao.create(tournament);
    }
}

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

private IEventSchedulerDao dao = EventSchedulerDao.getInstance();

Я все еще должен был бы использовать IEventSchedulerDaoэкземпляр, но я предполагаю, что все одиночные игры работают как это правильно? По какой-то причине я всегда сопоставляю синглтоны со статическими методами, поэтому вместо того, чтобы одноэлементный экземпляр был видим для пользователя getInstance(), он будет скрыт, и он / она будет просто использовать EventSchedulerDao.get(name)и т. Д. ... в статическом режиме. Это вещь или это только я?

Итак, я должен или не должен иметь одиночные DAO?

И как побочный вопрос, хорошо ли мой подход, чтобы у пользователя были открытые двери для реализации своих собственных DAO?

dabadaba
источник
Вы можете использовать синглтон IoC вместо синглтона со статическим средством доступа.
CodesInChaos

Ответы:

10

Я бы не использовал синглтон. Это признанный анти-паттерн , который затрудняет тестирование. Я бы предпочел внедрить в конкретную реализацию и сделать так, чтобы ваш сервис ссылался на интерфейс DAO (позволяя вам внедрять различные реализации в)

Брайан Агнью
источник
1
Что вы предлагаете в своем последнем предложении, это именно то, что я делаю правильно?
Дабадаба
1
Вы ссылки через интерфейс (да), но вы не инъекционного дао (быть понятно ....)
Brian Agnew
Что вы имеете в виду? У меня есть сеттер для этого, не так ли?
Дабадаба
@dabadaba Строка private IEventSchedulerDao dao = new EventSchedulerDao();, где вы ошиблись. Реализация for IEventSchedulerDaoдолжна быть введена через конструктор и никогда не изменяться (т.е. избавляться от нее setEventSchedulerDaoтоже).
Дэвид Арно
Хорошо, я понял. Я просто сделал это, чтобы предоставить DAO по умолчанию и изменить его было бы «необязательно». Но принять ваше предложение означает иметь конструктор для сервиса, отличный от стандартного, и, честно говоря, я понятия не имею, как это работает с Джерси, потому что он использует конструктор по умолчанию. Вы случайно не знаете, как это сделать?
Дабадаба
4

D ата ступа O ▪ Таблица должна только действительно существует один раз в вашем приложении. Логика остается той же, единственное, что отличается, это значения, входящие и выходящие из методов, которые предоставляет DAO.

Имея это в виду, очевидно, что первое, что обычно происходит, это реализация DAO как сильного синглтона , то есть когда у вас есть staticметод в классе фабрики, что-то вроде getInstanceленивой загрузки экземпляра DAO, если он нулевой, и его возвращения.

Извините, если синтаксис не совсем правильный, я не программист на Java.

class DaoSingletonFactory
{
    private static Dao dao = null;

    public static Dao getInstance()
    {
        if (DaoSingletonFactory.dao == null) {
            DaoSingletonFactory.dao = new Dao();
        }

        return DaoSingletonFactory.dao;
    }
}

class UsesDao
{
    public void someMethod()
    {
        Dao dao = DaoSingletonFactory.getInstance();
    }
}

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

Тогда есть лучший способ, слабый шаблон синглтона , где вы не извлекаете экземпляр с помощью staticметода, а делаете так, чтобы все классы зависели от экземпляра с помощью конструктора или метода установки (в вашем случае EventSchedulerServiceвы используете инъекцию метода установки).

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

Очевидно, что это невероятно сложно отследить, и построение граф-объекта является утомительной и раздражающей работой.

К счастью, есть контейнеры IoC , которые делают это намного проще. Помимо Spring , контейнер Guice IoC от Google довольно популярен среди Java-программистов.

При использовании контейнера IoC вы настраиваете его на определенное поведение, т.е. вы указываете, как предполагается создать определенные классы и требуется ли какой-либо класс в качестве зависимости, как должна выглядеть зависимость (должна ли она быть всегда новым экземпляром или единичным объектом) и контейнер связывает все это.

Вы можете проверить эту ссылку для одного примера с Guice.


Плюсы и минусы использования контейнера IoC

Pros

  • экономия бюджета за счет того, что не нужно писать все заводские методы самостоятельно
  • (обычно) очень простая конфигурация
  • быстрое развитие

Cons

  • волшебство волшебника, классы как-то сконструированы, и вы не можете увидеть, как это произошло
  • небольшое снижение производительности из-за поиска классов (фабрики, написанные вручную, будут немного быстрее)
Энди
источник
1

Синглтон ссылается на концепцию только одного экземпляра и способа получить доступ к экземпляру (через столь известный статический метод getInstance () )

Но за всем этим есть еще пример. Построенный объект с ограниченным доступом.

В вашем случае я бы предпочел использовать подход DI (внедрение зависимостей). Как и первый блок кода, который вы раскрыли. Просто небольшое изменение. Внедрить DAO через конструктор. Удалять или нет сеттер зависит от вас. Если вы хотите защитить контроллер от изменений во время выполнения, удалите его. Если вы хотите предложить такую ​​возможность, то сохраните ее.

Вы правильно используете интерфейс и предлагаете открытое окно для дальнейшей реализации DAO. Может или не нужно. Это займет всего одну минуту больше работы, но это делает ваш дизайн гибким. Ваш в памяти DAO довольно распространен. Очень полезно, как макет во время тестирования. Или как стандартная реализация DAO.

Просто намек. Статические ресурсы (объекты, методы, константы или переменные) похожи на глобальные ресурсы. Если глобальные злые или нет, это вопрос потребностей или вкусов. Однако с ними связаны неявные недостатки. Они связаны с параллелизмом , безопасностью потоков (в Java, не знаю о других языках), сериализацией ...

Поэтому я бы предложил использовать статику осторожно

LAIV
источник