我的调度员正在“选择”正确的控制器;然后创建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);
}
答案 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经常更改,您的解决方案对我都有好处。