Где должен быть мой код конструкции объекта при соблюдении закона Деметры? - PullRequest
2 голосов
/ 29 мая 2011

Я наблюдал за чистыми кодами Google от Misko Hevery. В этих беседах говорится: запросите зависимости в конструкторе, чтобы другие программисты могли заранее увидеть, что именно нужно, для создания экземпляра данного объекта ( закон деметра ). Это также облегчает тестирование, так как программист точно знает, что нужно смоделировать.

Пример времени
Если у меня есть класс Customer, и у меня также есть класс CustomerDAO для абстрагирования доступа к данным. Когда я создаю объект customer, я могу сделать следующее:

database = new Database('dsn');
customerDao = new CustomerDAO(database);
customer = new Customer(customerDao);

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

Должен ли я добавлять свои зависимости класса домена (в данном случае объекты DAO) в мой контейнер DI? Если мое приложение большого размера, это сделает мой DI-контейнер огромным?

При использовании DI-контейнера мой код может выглядеть следующим образом:

// container setup
container->dsn = '...';
container->dbh = function($c) {
    return new Database($c->dsn);
};
container->customerDao = function($c) {
    return new CustomerDAO($c->dbh);
};

// controller code
class ControllerCustomer extends ControllerBase {

    public function index() {
        container = this->getContainer();
        customer = new Customer(container->customerDao);
        view->customerName = customer->getName();
        view->render();
    }

}

Кажется, все в порядке, если другой программист хочет проверить Customer, им нужен только макет CustomerDAO.

Если продолжить этот пример, если у меня есть доменные классы с зависимостями от других доменных классов, конечно, мой контейнер DI не должен знать, как создать каждый класс домена? Например:

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

class Customer {

  protected _dao;

  public function Customer(dao) {
    _dao = dao;
  }

  public function listUsers() {
    userIds = _dao->getAllUserIds();
    users = array();
    foreach (userIds as uid) {
      user = new User(new UserDAO(new Database('dsn')); // problem
      users[] user->load(uid);
    }
    return users;
  }

}

Проблемы

  1. Так как я не передал свой DI-контейнер моему Customer -объекту, он не может создавать пользовательские объекты, как показано выше, так как не имеет ссылки на DSN базы данных (и на самом деле не должен знать, как это сделать). пользователей)
  2. Создание собственных зависимостей делает этот код непроверенным, поскольку он конкретный, без швов для насмешек.
  3. Если я передам контейнер моему классу Customer, это делает мой интерфейс для Customer ложью? (См. 9:15 в связанном видео Google).

Должен ли я передавать фабрику пользователей в Customer, чтобы она могла создавать User объекты?

database = new Database('dsn');
userDao = new UserDAO(database);
userFactory = new UserFactory(userDao);
customer = new Customer(customerDao, userFactory);

Должна ли конструкция для UserFactory находиться в моем контейнере DI?

1 Ответ

0 голосов
/ 30 мая 2011

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

DDD - это один из подходов к проектированию, который дает очень предписывающее руководство о том, как подходить к таким проблемам; в вашем случае соответствующими понятиями являются репозитории и совокупные корни. Хотя DDD, вероятно, не ответит на ваш вопрос напрямую, вам будет гораздо проще найти решение на основе шаблонов, соответствующее вашим требованиям.

Я намеренно не пытаюсь объяснить DDD вообще или концепции, которые я упомянул; об этом имеется достаточно материалов на SO и в других местах.

...