Не слишком ли много зависимостей для внедрения в объект через конструктор? - PullRequest
9 голосов
/ 18 января 2011

Я работаю над проектом типа социальной сети на OO PHP и не хочу использовать существующую платформу.Основная цель этого проекта - помочь мне узнать больше.

Этот вопрос больше касается внедрения зависимостей.

Допустим, у меня есть эти классы:

базовый класс - некоторые основные методы для работы в приложении
класс конфигурации - загрузканастройки сайта
класс базы данных - подключается к mysql и выполняет все связанные с базой вещи
класс ведения журнала - используется для регистрации ошибок и отладочной информации
captchaкласс - для капчи в формах
класс сеанса - инициирует начало сеанса и добавляет, удаляет, получает переменные сеанса для использования в приложении
класс кэша -похож на сессионный класс, но для элементов кэша (кеш файлов, memcache, apc кеш. Я могу даже когда-нибудь добавить свой сессионный материал в этот класс, так как все эти кеш могут использовать методы одного типа)

Все классы вышеСкорее всего, будет использоваться при каждой загрузке страницы в моем приложении (возможно, я пропустил еще несколько классов, которые будут добавлены позже)

Теперь в дополнение к вышеперечисленным классам, которые нужно будет внедрить в большинство других классов,Я будуУ меня будет еще много классов.У меня будет секция под названием Модули, которая будет иметь такие вещи, как ...

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

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

Так должен ли я использовать реестр для хранения объектов из первого набора классов и просто внедрить реестр во все объекты классов во втором наборе классов?

Или я должен использовать конструктор для их загрузки?В этом примере было бы около 7 объектов для внедрения в другие классы, что выглядит много.Я иду по этому поводу неправильно?

--- EDIT ---
Мне известно о синглтоне, но я не думаю, что это мой лучший вариант здесь

--- РЕДАКТИРОВАТЬ 2 ---
Как некоторые уже упоминали, необходимость передавать целых 7 объектов кажется МНОГО, и именно поэтому я ищу предложения.К счастью для меня, этот проект находится на начальной стадии, поэтому сейчас время для изменений в структуре.

Примером будет класс в разделе моего форума.Класс форумов должен иметь доступ к данным сеанса, возможным кэшированным данным, объекту config, объекту базы данных.Я поступаю неправильно?

Ответы [ 2 ]

11 голосов
/ 18 января 2011

Или я должен использовать конструктор для их загрузки?В этом примере было бы около 7 объектов для внедрения в другие классы, что выглядит много.Я ошибаюсь?

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

Если это действительно невозможно, рассмотрите возможность инкапсуляции связанных объектов в другом классе.Возможно, ваши сеанс, логгер и объекты конфигурации могут быть внедрены в объект App или Application?

Редактировать: Я заметил, что большинство других ответов пока говорят о синглетонах.Обратите внимание, что синглтоны являются врагом DI.Отличный технический доклад Google по этому вопросу здесь .

Редактировать 2:

То, что я имею в виду под инкапсуляцией, вместо введения Session, Logger, Config и т. Д. Все в ваш класс Account, может быть, они должны быть введены в класс Application, а экземпляр Application может быть введен в Account.

ВЧестно говоря, это все еще часть ДИ, я оборачиваюсь вокруг меня, но то, что я начинаю видеть, таково: вам следует вводить только в Account объекты, которыми он будет напрямую манипулировать.Этим объектам, возможно, придется манипулировать еще другими объектами, но Account не нужно знать об этом.


Часто вы обнаружите, что вам даже не нужно столько "слоев", сколькоВы думали, хотя.Если вы обнаружите, что вводите что-то повсюду, подумайте о различных способах реструктуризации вашего приложения.Позвольте мне взять фрагмент кода из документации Pylons для модели:

a = model.Person()
a.name = "Aaa"
a.email = "aaa@example.com"
meta.Session.add(a)

(Не беспокойтесь о meta.Session ... в основном это обрабатывает взаимодействие с базой данных.)

Здесь мы создаем Person, устанавливаем пару его атрибутов, а затем сохраняем их.Вы заметите, что Person класс не знает ничего о базе данных, и на самом деле даже не имеет save() метода.Вместо этого мы передаем его в класс базы данных (meta.Session), который сохраняет его.Мы отделили заботу о Person логике от кода базы данных.meta.Session может работать с дюжиной разных способов, но пока он умеет читать Person, у нас все хорошо.(в этом случае, во время инициализации приложения, он читает определение всех моделей приложения).


Хорошо, я собираюсь подвести итог, потому что я, очевидно, много здесь прогулял.Не существует одного «правильного» ответа на ваш вопрос (насколько я знаю, но я не провозглашаю себя экспертом DI каким-либо образом).

Да, введение нескольких объектов, вероятно, указывает на некоторыенужно реструктурировать, но у вас есть ряд соображений:

  • Является ли объект, получающий инъекцию, ответственным за слишком много;это может быть выделено?
  • Вы вводите только те объекты, которые класс получателей должен будет использовать напрямую?
  • Вы вводите неправильное направление;Может ли ваш Account объект быть введен в ваш Database, а не наоборот?
0 голосов
/ 18 января 2011

Я всегда предпочитал подход с использованием реестра.

Причины:

  • Большой объем
  • Просто получить
  • конструкторы освобождаются от использования объектов в качестве переменных (допускает лучшее использование)
  • Позволяет вам использовать больше объектов в ваших классах как бесплатное, чтобы захватывать то, что вам нужно, когда вы хотите.

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

Для примера создайте интерфейс примерно так:

interface ISingleton
{
    public static getInstnace();
}

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

class SomeObject implements ISingleton, ISomeThingElse
{
    private static $_instance;
    public static getInstance()
    {
        if(self::$_instance === null)
        {
           self::$_instance = new SomeObject(); 
        }
        return self::$_instance;
    }
}

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

Пример: * * тысяча двадцать-пять

public function GetUser($id)
{
    return Database::getInstance()->fetchUserById($id);
}

Надеюсь, это поможет.


Есть еще один способ, который вы можете сделать, это создание контекстного класса, позвольте мне попытаться объяснить:

Класс будет действовать как реестр, но одноразовый, например:

class Context
{
    private $objects = array();

    public function Add($key,$Object)
    {
        $this->objects[$key] = $object;
    }

    public function __get($key)
    {
        return isset($this->objects[$key]) ? $this->objects[$key] : null;
    }
}

И используйте это как контейнер для хранения ваших объектов следующим образом:

$Context = new Context();
$Context->Add("database",$database);
$Context->Add("logger",$logger);
$Context->Add("session",$session);

$UserObject = new RegularUser($Context);

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

...