在构造函数中实例化对象是不是很糟糕?如下所示?
class Foo
{
public function fooMethod() {
return 'foo method';
}
}
class Too
{
public function tooMethod() {
return 'too method';
}
}
class Boo
{
public $foo;
public $too;
public function __construct()
{
$this->foo = new Foo();
$this->too = new Too();
}
}
如果是这样,它有多糟糕?该如何正确完成?
答案 0 :(得分:3)
手动实例化另一个类中的类会创建隐式依赖项,这很难维护 - 如果您需要更改那些Foo
和Too
,您将很难检测到需要更改的内容类。
因此,管理依赖关系的更好方法是:
class Foo
{
private $_bar;
function __construct(Bar $bar)
{
$this->_bar = $bar;
}
}
这样,您的对象依赖是显式的。这样做的另一个好处是,一些PHP框架(Laravel,Zend,Symfony)允许自动依赖性解析。这意味着,您不能手动实例化您的对象,只能通过某种工厂 - 像这样(Laravel):
$foo = App::make('Foo');
App
工厂会使用一些反射魔法自动检测您的Foo
类依赖关系并适当地注入它们。其他框架也有类似的功能。
此外,OOP中有一些通用原则,称为SOLID
,有助于开发更好的OOP设计。其中一个 - D
代表Dependency Inversion
。这意味着,你应该避免hard
依赖,就像你的代码一样。相反,Foo
和Bar
类都应该依赖于interface
,如下所示:
interface BarInterface
{
function doBar();
}
class Bar implements BarInterface
{
function doBar()
{
print "Doing BAR";
}
}
class Foo
{
/**
* @var BarInterface
*/
private $bar;
function __construct(BarInterface $bar)
{
$this->bar = $bar;
}
}
现在,如果你需要用其他东西改变那个Bar
课程,如果你的替代者也实现BarInterface
,那么一切都不会破裂。
答案 1 :(得分:2)
这本身并不坏。
缺点是它会降低班级的“可测试性”,因为Boo
现在依赖于存在Foo
和Too
。
答案 2 :(得分:2)
这取决于项目的大小。
对于大型项目或长期项目,应略有改变。
理想情况下,您可以重构它实现Dependency Injection pattern,并可能使用Factory来实例化它。
一些示例代码:
interface FooInterface { function fooMethod(); }
class Foo implements FooInterface { function fooMethod(){return 'Foo';} }
interface TooInterface { function tooMethod(); }
class Too implements FooInterface { function tooMethod(){return 'Too';} }
class Boo
{
public $foo;
public $too;
public function __construct(FooInterface $foo, TooInterface $boo)
{
$this->foo = $foo;
$this->too = $boo;
}
}
class BooFactory
{
public static function create()
{
return new Boo(new Foo, new Too);
}
}
答案 3 :(得分:1)
这取决于您的要求和课程。 让我们说每次调用Foo / Too的构造函数都会对数据库执行一个巨大的查询来获取数据,在这种情况下我会选择使用lazy instantiation。
当然,在构造函数中初始化属性是一种很好的做法,但在现实生活中可以表现出你的敌人。
示例:
class Boo {
private $foo = null;
private $too = null;
public function __construct() {
//Do something else
}
public function getFoo() {
if (is_null($this->foo)) {
$this->foo = new Foo();
}
return $this->foo;
}
public function getToo() {
if (is_null($this->too)) {
$this->too = new Too();
}
return $this->too;
}
public function aMethodThatUsesFoo() {
$foo = $this->getFoo();
$foo->fooMethod();
}
public function aMethodThatDoesntUsesFoo() {
echo "Hello!, I don't need foo or too to execute this method";
}
}
如果你只使用这个类来执行aMethodThatDoesntUsesFoo()
,它永远不会调用Foo / Too的构造函数。
$boo = new Boo();
$boo->aMethodThatDoesntUsesFoo();
如果您只执行aMethodThatUsesFoo()
,它只会实例化Foo
$boo = new Boo();
$boo->aMethodThatUsesFoo();
您也可以通过静态方法执行此操作。