MVC,DI(依赖注入)和从Controller创建Model实例

时间:2010-03-09 12:32:29

标签: php model-view-controller dependency-injection

我的调度员正在“选择”正确的控制器;然后创建Controller的实例(DependencyInjectionContainer传递给Controller构造函数);然后调用一些Controller的方法......

class UserController extends Controller
{

  public function __construct(DependencyInjectionContainer $injection) {
    $this->container = $injection;
  }

  public function detailsAction() {
    ...
  }

}

DependencyInjectionContainer包含DB适配器对象,Config对象等。 现在让我们看看detailsAction()方法包含的内容......

public function detailsAction() {

  $model = new UserModel();
  $model->getDetails(12345);

}

如您所见,我正在创建UserModel的新实例并调用getDetails方法。 Model的getDetails()方法应连接到db以获取有关用户的信息。连接到DB UserModel应该能够访问DB适配器。

将DependencyInjectionContainer传递给UserModel的正确方法是什么? 我认为这种方式是错误的......

public function detailsAction() {

  $model = new UserModel($this->container);
  $model->getDetails(12345);

}

2 个答案:

答案 0 :(得分:10)

您应该仅注入所需的依赖项,而不是将整个DI容器注入到您的类中。

您的UserController需要数据库适配器(让我们调用此接口IDBAdapter)。在C#中,这可能是这样的:

public class UserController
{
    private readonly IDBAdapter db;

    public UserController(IDBAdapter db)
    {
        if (db == null)
        {
            throw new ArgumentNullException("db");
        }

        this.db = db;
    }

    public void DetailsAction()
    {
        var model = new UserModel(this.db);
        model.GetDetails(12345);
    }
}

在这种情况下,我们将依赖项注入UserModel。但是,在大多数情况下,如果UserController只接受依赖项传递它,我倾向于认为它是DI气味,因此更好的方法可能是UserController依赖于像这样的抽象工厂:

public interface IUserModelFactory
{
    UserModel Create();
}

在此变体中,UserController可能如下所示:

public class UserController
{
    private readonly IUserModelFactory factory;

    public UserController(IUserModelFactory factory)
    {
        if (factory == null)
        {
            throw new ArgumentNullException("factory");
        }

        this.factory = factory;
    }

    public void DetailsAction()
    {
        var model = this.factory.Create();
        model.GetDetails(12345);
    }
}

你可以定义一个具体依赖IDBAdapter的UserModelFactory:

public class UserModelFactory : IUserModelFactory
{
    private readonly IDBAdapter db;

    public UserModelFactory(IDBAdapter db)
    {
        if (db == null)
        {
            throw new ArgumentNullException("db");
        }

        this.db = db;
    }

    public UserModel Create()
    {
        return new UserModel(this.db);
    }
}

这样可以更好地分离关注点

如果需要多个依赖项,只需通过构造函数注入它们即可。当你开始变得太多时,表明你违反了Single Responsibility Principle,现在是时候refactor to Aggregate Services了。

答案 1 :(得分:0)

我会为所有配置参数使用单例对象: 您可以在引导程序中进行设置,然后选择直接使用它或将其作为参数传递给对象。

想法是使用一种方法来检索配置数据。

然后,您可以为使用您的配置的数据库操作提供一个抽象类。单身。 DependancyInjection仍可用于覆盖您的默认数据。

注释中的上述链接(可能是“重复”)在使用构造函数注入时结束:这与您当前的方法很接近。

但是如果我试图弄清楚你的模型是如何工作的,我猜你会有除“userModel”以外的许多其他模型类。因此,使用配置单例的抽象类可能是一个很好的解决方案:所有下一个模型类都只是扩展这个抽象类,你不必担心你的配置。

另一方面,只要您的dependanceInjectionContainer经常更改,您的解决方案对我都有好处。