Как получить доступ к моим синглетонам без использования глобального состояния? - PullRequest
4 голосов
/ 25 июля 2010

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

Мой вопрос заключается в том, как я могу получить доступ к своему объекту в низкоуровневых классах (глубоко в графе объектов), не передавая все этоПоверхность?

Допустим, у меня есть контроллер приложения, который на самом деле создает (запрашивает у фабрики его экземпляр) контроллер страницы, который запускает модель User, для которой требуется объект базы данных.

Ни мойКонтроллер приложения и мой контроллер страницы не должны знать об объекте базы данных, но класс User знает.Как я могу передать объект ему?

Спасибо за ваше время!

Ответы [ 5 ]

4 голосов
/ 25 июля 2010

Рассмотрите возможность использования глобального контейнера:

  • Вы регистрируете объекты, которые действительно относятся к нескольким подсистемам приложения.
  • Затем вы запрашиваете этот контейнер для этих объектов.

Этот подход очень популярен в средах внедрения зависимостей (см. Symfony DI, Yadif).

2 голосов
/ 25 июля 2010

Singleton - это плохо, без сомнения об этом.

В случае, который вы описываете, объект базы данных является подробностью реализации объекта User.Вышеприведенные уровни должны знать только о пользователе, а не об объекте базы данных.

Это становится намного более очевидным, если вы скрываете пользовательский объект за интерфейсом и используете этот интерфейс только из слоев выше.

Таким образом, контроллер страницы должен иметь дело только с интерфейсом, а не с конкретным классом, который зависит от объекта базы данных, но как создавать новые экземпляры?Он использует вставленную Abstract Factory для создания экземпляров интерфейса.Он может иметь дело с любой реализацией этого интерфейса, не только той, которая опирается на объект базы данных.

Еще раз, вы скрываете контроллер страницы за интерфейсом.Это означает, что зависимость конкретной реализации от абстрактной фабрики становится еще одной деталью реализации.Контроллер приложений использует только интерфейс контроллера страницы.

Вы можете продолжать обтекание таких объектов без необходимости передавать экземпляры.Только в Root Composition вам нужно связать все зависимости вместе.

Смотрите здесь для получения связанного ответа с примерами на C #: Лучше ли создавать синглтон для доступа к единицеконтейнер или передать его через приложение?

0 голосов
/ 05 августа 2010

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

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

Создайте IUserFactory, который создает реализации IUser, и передайте это в свой PageControllerFactory, тогда вашему ApplicationController нужно знать только о PageControllerFactory, ему не нужно ничего знать о IUserFactory или базе данных.

Затем при запуске приложения вы можете создать все свои зависимости и внедрить их друг в друга через конструкторы.

0 голосов
/ 26 июля 2010

Для загрузки / сохранения пользователя с использованием базы данных используются два основных объекта: пользователь и хранилище.

Похоже, вы реализовали функциональность для пользователя, но я думаю, что он принадлежит хранилищу. Вы должны передать пользователя в хранилище, чтобы сохранить его.

Но как вы заполучили хранилище? Он создается один раз на верхнем уровне и передается службам, которые в этом нуждаются.

Граф зависимостей построения и граф зависимостей вызовов не одно и то же.

0 голосов
/ 25 июля 2010

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

class deeply_nested_class {

открытая функция some_function () {

$ singleton = Singleton :: getInstance ();

}

}

...