2

我一直在看 Misko Hevery 的 Google 的干净代码演讲。这些谈话说:在构造函数中请求依赖项,以便其他程序员可以预先准确地看到需要什么来实例化给定对象的实例(demeter 定律)。这也使测试更容易,因为程序员确切地知道需要模拟什么。

示例时间
如果我有一个类Customer并且我也有一个CustomerDAO类来抽象数据访问。当我构造一个客户对象时,我可能会执行以下操作:

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,他们只需要 mock 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谎言?(请参阅链接的 Google 视频中的 9:15)。

我应该传递用户工厂以Customer使其能够构造User对象吗?

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

UserFactory应该在我的 DI 容器中构建吗?

4

1 回答 1

0

如果我对此的解释正确,那么您的问题似乎实际上是关于实体构建和生命周期管理的。

DDD 是一种设计方法,它为如何处理此类问题提供了非常规范的指导;在您的情况下,相关概念是存储库和聚合根。虽然 DDD 可能不会直接回答您的问题,但它会让您更轻松地提出符合您要求的基于模式的解决方案。

我故意不试图解释一般的 DDD 或我提到的概念;SO和其他地方有足够的材料。

于 2011-05-29T20:08:36.613 回答