我有一个问题:我是否需要为应用程序中的每个对象配置DI / IoC容器或只配置工厂?
现在我有这样的事情:
'serviceFactory' => function() use ($container) {
return new \Application\Core\Factory\ServiceFactory($container->get('entityFactory'), $container->get('repositoryFactory'), $container->get('cache'), $container->get('file'), $container->get('image'));
},
'repositoryFactory' => function() use ($container) {
return new \Application\Core\Factory\RepositoryFactory($container->get('database'), $container->get('queryBuilder'), $container->get('mapper'), $container->get('language'));
},
'entityFactory' => function() use ($container) {
return new \Application\Core\Factory\EntityFactory($container->get('language'));
},
但是,应用程序会将不必要的对象加载到其他不需要的对象中。
示例:在 BlogService 中,我不使用文件类或图像类。在 ThumbnailService 我这样做,但我不在其中使用实体或存储库。
那么,我是否需要在DI / IoC容器中导入一些延迟加载,或者我需要像这样编写每个Entity / Repository / Service / Controller连接:
'blogController' => function() use ($container) {
return new \Application\Controller\BlogController($container->get('blogService'));
},
'blogService' => function() use ($container) {
return new \Application\Service\BlogService($container->get('blog'), $container->get('categoryEntity'), $container->get('blogRepository'), $container->get('cache'));
},
'blogRepository' => function() use ($container) {
return new \Application\Model\Repository\BlogRepository($container->get('database'), $container->get('queryBuilder'), $container->get('mapper'), $container->get('language'));
},
'blog' => function() use ($container) {
return new \Application\Model\Entity\Blog($container->get('language'));
},
'thumbnailService' => function() use ($container) {
return new \Application\Service\ThumbnailService($container->get('image'), $container->get('file'));
},
但是这样我可以编写所有50-100个实体,存储库,服务和控制器,可能会过度优化?
有什么建议吗?
答案 0 :(得分:1)
不,通常您只需要注册可以变化的类型,即抽象的具体实现。如果你没有使用抽象,那么DI容器就没用了。
DI容器应该允许使用约定来注册类型,例如将所有在“服务”中需要名称的类注册为服务。这样,您只需定义一些“规则”,无论您在应用程序中拥有多少服务,都会自动完成注册。至少这是.net中的事情,但显然手动编写50-100个类的注册是一种代码味道。
<强>更新强>
看起来应该是这样的
interface ISomeService {}
class MyService implements ISomeService { }
class OtherService
{
private $svc;
function __construct(ISomeService $svc)
{
$this->svc=$svc;
}
function doStuff()
{
//do stuff using $this->svc
}
}
//DiContainer
//here you you should register things (I don't know a container for php, I'll write what I'm using in C#, but you'll get the idea)
container.RegisterTypes(myAssembly)
.Where(type=>type.Name.EndsWith("Service"))
.AsSelf()
.AsImplementedInterfaces();
上面的代码告诉容器扫描名称以“Service”(我的约定)结尾的所有类,并自动注册它们,以便在请求特定类型或由其实现的接口实现时使用类型。
在我们的示例中,这意味着当从容器请求 OtherService 的实例时,容器知道使用 MyService 类型作为的具体类型ISomeService 。容器会查看构造函数以检测对象需要的依赖项。
为了正确使用DI容器,您的(mvc)框架应该知道它,因为它不应该由您的应用程序直接使用。在某些情况下,服务定位器模式有效,但通常框架应使用容器来创建所需服务的实例。
您在应用程序引导时(作为部分或与您的mvc框架集成)配置容器,就是这样。接下来,您只需定义接口和类(服务,存储库,事件处理程序等)。您应该做的唯一事情是提出一些约定,允许容器根据它们自动注册类(例如命名服务“服务”)。
DI容器首次出现在静态类型语言(java,C#)中,与使用不受类型限制的动态语言相比,使用起来更有意义(这就是我在php中使用类型提示的原因) )。它们仍然有用,但有点难以理解。