我有两堂课
ClassA , ClassB类通常依赖于两个基本服务和存储库。
ServiceA , ServiceB类(ClassA , ClassB)使用DI原则使用构造函数注入依赖项。
由于所有这三种方法都共享一些公共服务,所以我想将所有公共方法和服务分组到一个类Base中,如下所示
基类
class Base {
protected $A;
protected $B;
public function __construct(ServiceA $A, ServiceB $B){
$this->A = $A;
$this->B = $B;
}
}儿童服务
class Child extends Base {
protected $C;
public function __construct(ChildDependency $C){
$this->C = $C;
}
public function doStuff()
{
//access the $A (**Its null**)
var_dump($this->A);
}
}问题
如何在不违背IoC原则的情况下拥有共同的父依赖关系?
可能的案例1
我知道我必须调用parent::__construct()来初始化基本构造函数。但是,我必须在所有的子类中定义父母的依赖关系,如下所示。
(但对于大量的孩子,我不得不重复这个过程。它违背了具有共同DI点的目的)。
class Child extends Base {
protected $C;
public function __construct(ChildDependency $C, ParentDepen $A, ParentDepn $B){
parent::_contruct($A,$B);
$this->C = $C;
}
}可能的案例2
使用Getter和Setter。但我认为他们违反了IoC原则。
发布于 2015-02-07 08:01:38
如果您必须从创建对象的任何东西中注入依赖,这似乎是您的最佳选择:
class Child extends Base {
protected $C;
public function __construct(ServiceA $A, ServiceB $B, ChildDependency $C){
parent::__contruct($A, $B);
$this->C = $C;
}
}您可以尝试使用特征来代替:
trait ServiceATrait {
public $A = new ServiceA();
public function getServiceA() { return $this->A; }
}
trait ServiceBTrait {
public $B = new ServiceB();
public function getServiceB() { return $this->B; }
}
class Base {
use ServiceATrait;
use ServiceBTrait;
}
class Child extends Base {
protected $C;
public function __construct(ChildDependency $C) {
$this->C = $C;
}
}
function() {
$c = new Child(new ChildDependency());
echo $c->getServiceB()->toString();
}发布于 2015-02-25 11:24:39
为了保持继承场景中具有几个依赖项的整洁和可维护性,我个人更喜欢setter注入而不是构造函数注入。马丁·福勒对此也有一些想法,值得一读。
您还可以选择使用构造函数注入注入公共依赖项,以及使用setter注入注入子依赖项以避免与构造函数混淆。
然而,如果您使用setter注入,确保对象不被部分初始化或缺少某些依赖项是非常重要的。确保这在服务的getter方法中是一个很好的方法(尽管您只会在运行时注意到这一点)。通过对德里克的示例进行扩展,您可以定义您的getter如下:
trait ServiceATrait {
private $A;
public function initServiceA(ServiceA $serviceA) {
$this->A = $serviceA;
}
public function getServiceA() {
if (null === $this->A) {
throw new \LogicException("ServiceA has not been initialized in object of type " . __CLASS__);
}
return $this->A;
}
}无论您选择什么选项,都要确保在代码库中始终使用它。
发布于 2015-02-25 16:23:11
我不确定我是否理解您试图通过使用继承来完成什么任务。继承应该用于概念上相同类型的事物,而不是用于公共依赖注入点。如果您有一个使用继承的自然情况,并且您也希望使用依赖注入,以便遵循良好的实践,那么这是有意义的。但是,如果继承和构造函数参数是可行的,那么如果您有大量的继承,就不能绕过在许多类中更改它们。但是,拥有大量的继承通常是过度使用继承的一个标志。继承经常被过度使用。它使类的行为变得复杂,难以阅读和改变。始终寻找继承的替代方案,并且只在继承比替代方案工作得更好时才使用。
你又闻到了一股暗号味。如果您需要传递足够多的构造函数参数,从而造成可维护性问题,那么您的类可能违反了单一责任原则。这意味着您需要将您的类分解为更多的类。您还可能需要将一些构造函数参数更改为适当方法的方法参数。
正如其他人所提到的,你可以利用自己的特质。这将使您更容易只继承您想要的行为。这些特性既可以创建属性,也可以使用某些默认类型设置属性,并提供一种获取和设置这些属性的方法。
至于您对能够在运行时更改事物的担忧,我不知道您的意思。所有这些都在运行时运行。最后,所有这些都只是变量。可以在运行时调用构造函数,并且可以传递它们所需的任何值。您也可以在运行时使用setter。根据定义,依赖注入是一种运行时技术。如果您的类正在创建所讨论的类型,而没有提供通过DI更改类型的方法,那么我猜它在运行时是不可更改的,但没有人建议这样做。
您可以使用工厂类或静态工厂方法。静态工厂方法可以有不同的名称来描述如何构造它。工厂类可以有一个工厂方法,在这种情况下,您可以将工厂实例设置为任何正确构造对象的工厂。
不要忘记默认参数。无论您如何进行依赖注入或构造对象,都应该记住这些。示例:
class someClass {
public function _construct($serviceA = new serviceA()) {
$this->serviceA = $serviceA;
}
}https://stackoverflow.com/questions/28379409
复制相似问题