我正在尝试将第三方工具注入Silex中的自定义类。然后我计划在某个时候用另一个库替换这个工具。为了符合DI原则,为了解耦我的类和库,我将指定这些工具必须实现的接口。并在我的自定义类构造函数中键入提示接口。这将有助于我避免对我的课程进行任何更改。喜欢这个
for(i in 1:length(a$age))
{
ifelse(a$age<17, a$age_group<-"mid",
ifelse(a$age<20, a$age_group<-"high",
ifelse(a$age<24, a$age_group<-"univ",
a$age_group<-"worker")))
}
要注册这些第三方库,我必须为每个库创建服务提供商。然后我似乎需要某种适配器来使这些工具符合MyCustomInterface所规定的合同。事实证明,每个第三方乐器我必须管理2个额外的类(提供者和适配器)。
我的问题是:
我的DI概念完全正确吗?
是否可以简化此解决方案?
Silex是否能够通过'适配器'来管理这种情况?
答案 0 :(得分:1)
据我所知,你的DI概念正确。如果您不想在每次更改库时重构整个代码(以及使用您的库的代码),那么适配器就是最佳选择:您可以使用每个适配器必须实现的接口定义特定的API 。通过这种方式,您可以安全地调用接口方法,而无需了解后面的实现。所以恕我直言,这是要走的路,你再次来到这里(但我认为你的Silex环境中的解决方案可以简化,是的,Silex可以管理这个,任何其他现代框架也应如此)。 / p>
为了简化您提出的解决方案,我不会为每个实现创建不同的提供程序。提供程序将您的库与Silex绑定在一起,您只需告诉提供程序必须使用哪个适配器(实现),您可以使用参数执行此操作(请参阅代码示例末尾的注释)。所以我会选择这样的东西:
<?php
namespace Acme;
use Silex\Application;
use Silex\ServiceProviderInterface;
use Acme\MyCustomInterface; // This is your library interface
class MyCustomLibraryServiceProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app['some_dependency'] = $app->protect(function() use ($app) {
// do whatever to create a new instance of this dependency
});
$app['another_dependency'] = $app->protect(function() use ($app) {
// do whatever to create a new instance of this dependency
});
$app['my_service'] = $app->protect(function () use ($app) {
// assuming your adapter has 2 dependencies.
$myService = new $app['my_service_class']($app['some_dependency'], $app['another_dependency']);
if (!$myService instanceof MyCustomInterface) {
throw new \RuntimeException("The 'my_service_class' parameter must implement MyCustomInterface!");
}
return $myService;
});
}
public function boot(Application $app)
{
}
}
然后,当您创建$ app实例时(可以根据需要创建尽可能多的适配器):
<?php
//...
use Acme\MyCustomLibraryServiceProvider;
//...
$app->register(new MyCustomLibraryServiceProvider(), [
'my_service_class' => "Acme\MyCustomLibraryAdapter1"
]);
请注意,此解决方案假定每个适配器都具有相同的依赖项。如果不是这种情况,您需要为每个适配器创建另一个提供商,但如果您不想这样做,请继续阅读: - )
如果您想进一步简化此操作,请考虑到您不需要创建提供商。如果您的库没有依赖项或只有1或2,您可以直接在创建应用程序实例的同一文件中创建服务(恕我直言,只有在创建服务的代码很重时,提供程序才有用):
<?php
//...
use Silex\Application;
use Acme\MyCustomLibraryAdapter1;
$app = new Application();
//...
$app['my_service'] = $app->protect(function() use ($app) {
$dep1 = new WhatEver();
return new MyCustomLibraryAdapter1($dep1);
});
此解决方案不太优雅,但更简单(您需要更改为每个适配器创建服务的代码)。