99%的我的依赖是通过@Autowired Spring注释用DI模式管理的.
然而,在特定情况下,我无法确定在运行时使用哪个实现.
最着名的情况是解析器的多重实现.
第一个解决方案是使用多个@Autowired(丑陋模式)
Interface Parser {
<T> T parse();
}
@Component("JsonParser")
class JsonParser implements Parser {
...
}
@Component("XmlParser")
class XmlParser implements Parser {
...
}
class MyService {
@Autowired
@Qualifier("XmlParser")
Parser xmlParser;
@Autowired
@Qualifier("JsonParser")
Parser jsonParser;
...
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我有大量的实现,那是不可接受的.
第二个解决方案是使用Spring的ServiceLocator
interface ParserServiceLocatorFactory {
public Parser getParser(String parserName);
}
interface Parser {
<T> T parse();
}
@Component("JsonParser")
class JsonParser implements Parser {
...
}
@Component("XmlParser")
class XmlParser implements Parser {
...
}
class MyService {
@Autowired
ServiceFactory parserServiceLocatorFactory; …
Run Code Online (Sandbox Code Playgroud) 是否有方法签名的意图的差异IServiceProvider.GetService(Type serviceType)
和IServiceLocator.GetInstance(Type serviceType)
?如果是这样,区别是什么?
我总是将它们视为等效的,但可以选择使用单一方法来保持一致性.对于处理这两个接口来说,这似乎是一个很好的解决方案,但我真的很想知道它们的用法是如何实际的,这样我才能确定我在正确的位置使用正确的用法. 如果他们的意图实际上是相同的,那么是否有任何理由为同一目的设置多组语义?(据我所知,在GetInstance
出现之初被推荐的签名Microsoft.Practices.ServiceLocation
,但是这并没有真正看起来像一个充分的理由,介绍重复).
以下是我在试图找到这个问题的答案时发现的有时相互矛盾的事实清单,以及我对此的解释.我将这些内容包含在内,以便可以在已知有关该主题的所有信息的上下文中解决我的问题.
在为MSDN文档IServiceProvider
说,该GetService(Type serviceType)
方法应该返回
serviceType 类型的服务对象.
- 或者 - 如果没有serviceType类型的服务对象,则返回
null.
在为MSDN文档IServiceLocator
缺少方法的文档,但在的VS对象浏览器中总结GetInstance(Type serviceType)
说,该方法返回"请求的服务实例".但是,文档IServiceLocator
中还有一个异常条目,表示ActivationException
如果解析服务实例时出错,则应抛出该条目.
ActivationException
位于Microsoft.Practices.ServiceLocation
引入多年后IServiceProvider
引入的命名空间中.因此,可以理解的是,IServiceProvider
它并未引用异常.话虽这么说,如果没有找到结果,IServiceLocator
界面的文档没有说明返回null
.还不清楚是否缺乏所要求的服务类型的实施应构成例外.
如果没有为服务类型的实现会导致ActivationException
在IServiceLocator
实现? 看起来不像.用于忽略非空后置条件的任何概念的实现模板IServiceLocator
.
该实施模板为IServiceLocator
也把IServiceProvider.GetService(Type)
作为替代语法IServiceLocator.GetInstance()
.这是否违反Liskov(由于在基类型上未声明的子类型中抛出异常),或者,实际上是否需要在实现中有所不同,而不是在接口的方法签名上声明的异常?我得到的是:我们确定实现的ServiceLocatorImplBase
实现模板IServiceLocator
都正确接口吗? …
c# dependency-injection common-service-locator service-locator base-class-library
我尝试基于Java构建和应用程序.
对于依赖注入,我使用Google Guice.
现在我想出了在应用程序期间记录一些信息的问题.我不会以方法调用等方式谈论一般日志记录.我知道AOP,我可以像方法调用跟踪一样.
我要找的是手动记录.我需要一些方法来记录我的应用程序中的几乎每个类.所以我想到了两个选择:
那么从实际角度来看,最好的方法是什么?
在创建可设计的.NET组件时,您需要提供默认构造函数.从IComponent文档:
要成为组件,类必须实现IComponent接口并提供不需要参数的基本构造函数或IContainer类型的单个参数.
这使得无法通过构造函数参数进行依赖注入.(可以提供额外的构造函数,但设计者会忽略它们.)我们正在考虑的一些替代方案:
服务定位器
不要使用依赖注入,而是使用服务定位器模式来获取依赖项.这似乎是IComponent.Site.GetService适用于.我想我们可以创建一个可重用的ISite实现(ConfigurableServiceLocator?),它可以配置必要的依赖项.但是这如何在设计师环境中起作用?
通过属性进行依赖注入
通过属性注入依赖项.如果需要在设计器中显示组件,请提供默认实例.记录需要注入哪些属性.
使用Initialize方法注入依赖项
这很像注入属性,但它保留了需要在一个地方注入的依赖项列表.这样,隐式记录了所需依赖项列表,编译器将在列表更改时帮助您解决错误.
知道最好的做法是什么吗?你怎么做呢?
Zend的优秀人员以及一些博主推荐ZF2的新服务定位器/管理器,而不是内置的依赖注入系统.
我的问题是,将模拟对象注入服务是否可行/方便?我在模块的PHPUnit引导程序中看到了一些略显笨拙的尝试.但有没有一种方法可以使用这种服务系统,比如ZF1 + Yadif干净方便?
phpunit dependency-injection service-locator zend-framework2
我真的很困惑何时使用getServiceLocator以及何时不使用.举个例子:
+ Module
-+ Helloworld
--+ src
---+ Controller
----+ IndexController.php
----+ IndexControllerFactory.php
---+ Service
----+ LogginService.php
----+ GreetingService.php
----+ GreetingServiceFactory.php
Run Code Online (Sandbox Code Playgroud)
GreetingServiceFactory.php有以下内容:
<?php
namespace Helloworld\Service;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class GreetingServiceFactory implements FactoryInterface
{
public function createService (ServiceLocatorInterface $serviceLocator)
{
$greetingService = new GreetingService();
$greetingService->setEventManager($serviceLocator->get('eventManager'));
$loggingService = $serviceLocator->get('loggingService');
$greetingService->getEventManager()->attach('getGreeting', array(
$loggingService,
'onGetGreeting'
));
return $greetingService;
}
}
Run Code Online (Sandbox Code Playgroud)
而IndexControllerFactory.php的内容如下:
<?php
namespace Helloworld\Controller;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class IndexControllerFactory implements FactoryInterface
{
public function createService (ServiceLocatorInterface $serviceLocator)
{
$ctr = new IndexController(); …
Run Code Online (Sandbox Code Playgroud) 我正在尝试将当前项目中的Dagger 2 替换为Koin,并且我不想在 Kotlin 中重写某些类来使用它。
可以在 Java 类中注入 Koin 吗?
在 Kotlin 中只是
// Inject MyPresenter
val presenter : MyPresenter by inject()
Run Code Online (Sandbox Code Playgroud)
谢谢
我习惯于在Web应用程序中使用IoC/DI - 主要是使用MVC3的Ninject.我的控制器是为我创建的,充满了所有依赖关系,子依赖关系等.
但是,胖客户端应用程序的情况有所不同.我必须创建自己的对象,或者我必须恢复到服务定位器样式方法,我要求内核(可能通过某个接口,允许可测试性)给我一个完整的依赖项对象.
但是,我已经看到Service Locator被描述为反模式的几个地方.
所以我的问题是 - 如果我想在我的胖客户端应用程序中受益于Ninject,是否有更好/更正确的方法来获得所有这些?
请注意我不只是在这里讨论MVVM并将视图模型放入视图中.这特别是需要从内核提供存储库类型对象,然后从该存储库中提取的实体注入了功能(当然数据来自数据库,但它们也需要一些对象作为参数,具体取决于状态世界,Ninject知道如何提供).我可以以某种方式做到这一点,而不会将存储库和实体都作为不可测试的混乱吗?
如果有什么不清楚,请告诉我.谢谢!
编辑7月14日
我确信提供的两个答案可能是正确的.然而,我身体的每一根纤维都在对抗这种变化; 其中一些可能是由于缺乏知识造成的,但也有一个具体原因导致我无法看到这种做事方式的优雅;
我没有在原始问题中解释得这么好,但问题是我正在编写一个库,将被几个(首先是4-5,可能更晚)的WPF客户端应用程序使用.这些应用程序都在相同的域模型等上运行,因此将它们保存在一个库中是保持DRY的唯一方法.但是,该系统的客户也有可能编写自己的客户端 - 我希望他们有一个简单,干净的库来与之交谈.我不想强迫他们在他们的作文根中使用DI(在他的书中使用像Mark Seeman这样的术语) - 因为与他们相比,只需要新建一个MyCrazySystemAdapter()并使用它就可以使事情复杂化.
现在,MyCrazySystemAdapter(因为我知道人们会在这里不同意我选择的名称)需要由子组件组成,并使用DI组合在一起.MyCrazySystemAdapter本身不需要注入.它是客户端与系统通信所需的唯一接口.因此,一个客户应该得到其中一个,DI就像魔术一样在幕后发生,并且该对象由许多不同的对象使用最佳实践和原则组成.
我确实意识到这将成为一种想要做事的有争议的方式.但是,我也知道将成为此API客户的人员.如果他们发现他们需要学习并连接DI系统,并在他们的应用程序入口点(Composition Root)中提前创建他们的整个对象结构,而不是新建一个对象,他们会给我中指和直接搞乱数据库并以你难以想象的方式搞砸了.
TL; DR:为客户端提供结构合理的API太麻烦了.我的API需要提供一个单独的对象 - 使用DI和适当的实践在幕后构建 - 他们可以使用.现实世界有时胜过为了坚持模式和实践而向后建造一切的愿望.
dependency-injection ninject testability thick-client service-locator
我不确定它是否只是我,但我感觉ASP.NET MVC控制器中使用的构造函数注入导致不必要的资源消耗.
在创建控制器时,仍然需要创建未用于特定Web请求的组件.当我渴望牛奶时,就像买摊位牛奶和果汁一样,然后我就扔掉果汁.
比较控制器的构造函数注入和服务定位器的这些示例,以澄清我的担忧.
public class MyController : Controller
{
private readonly IDep1 _dep1;
private readonly IDep2 _dep2;
public MyController(IDep1 dep1, IDep2 dep2)
{
_dep1 = dep1;
_dep2 = dep2;
}
public ActionResult Index()
{
_dep1.MakeStuff();
return View();
}
public ActionResult PageTwo()
{
_dep2.MakeStuff();
return View();
}
}
Run Code Online (Sandbox Code Playgroud)
public class MyController : Controller
{
public ActionResult Index()
{
var dep1 = ServiceLocator.Resolve<IDep1>();
dep1.MakeStuff();
return View();
}
public ActionResult PageTwo()
{
var dep2 = ServiceLocator.Resolve<IDep2>(); …
Run Code Online (Sandbox Code Playgroud) 我已经开始通过Symfony2代码,研究了像Pimple这样的小课程,经过几个小时的考试后出现了奇怪的想法.最好的开始是解释我如何理解一些术语,所以:
依赖性 另一种工作需要的东西,比如"汽车"中的"引擎"
容器 对象或能够存储许多其他对象的类,如"引擎","变速箱"甚至"汽车"
依赖注入 过程中每个依赖注入对象,所以如果我需要"汽车",我知道我必须注入"引擎","变速箱"和许多其他东西.重要的是,"汽车"不会创造"发动机",但"发动机"放在"汽车"里面
服务定位器 过程中对象要求另一个对象,例如进入汽车时插入我们的容器,当汽车需要启动时需要从容器"引擎",所以容器返回他的"引擎"
当我研究Symphony代码时,他们从依赖注入开始,但是经过一段时间我意识到当创建Controller时,会注入整个容器然后你可以使用$ this-> get('serviceName')来获取它,所以它更像是服务定位器,根据少数文章是反模式.
播种怎么回事?DI和SL之间的界限是否很小,有时会破坏?还是我误解了什么?如果我使用DI,我是否需要将每个服务插入控制器,所以我从外面知道我使用的是什么?或者控制器在某些情况下可以容器?
service-locator ×10
java ×3
.net ×1
android ×1
asp.net-mvc ×1
c# ×1
components ×1
frameworks ×1
koin ×1
kotlin ×1
logging ×1
ninject ×1
php ×1
phpunit ×1
spring ×1
symfony ×1
testability ×1
thick-client ×1