考虑以下类结构:
框架代码(蓝色区域)
应用程序代码:(黄色区域):
当前框架构造函数代码类似于:
class Database{
public function __constuctor (Logger $log, $databaseHost, $databaseUser, $databasePass, $databaseName){...}
}
class Redis{
public function __constuctor (Logger $log, $redisHost, $redisUser, $redisPass){...}
}
class ACME{
public function __constuctor (Database $db, Redis $redis, $otherStuff, ...){...}
}
在应用程序中,我们执行以下操作:
$logger = new Logger();
$db = new Database($logger, 'db_host','db_user','db_user','db_pass');
$redis = new Redis($logger, 'redis_host','redis_user','redis_pass');
$acme = new Acme($db,$redis, ...other_stuf...);
构造函数变得非常冗长和丑陋,我很想创建一个依赖容器(DI)并将其作为单个构造函数参数传递。
考虑原则:" 对象不应该知道包含它的依赖容器",我觉得不行,因为这只会取代当前具有新依赖项的多个依赖项 - 依赖项容器(DIC)本身。
我感觉很好,我可以在应用程序部分(图像的黄色部分)中使用DIC注入,但是不能将DIC注入基础框架代码(蓝色部分)。
我错了吗?
注入DIC可以吗?
在这里使用服务定位器模式是不是更好?
答案 0 :(得分:1)
在应用程序中,我们执行以下操作:
$logger = new Logger(); $db = new Database($logger, 'db_host','db_user','db_user','db_pass'); $redis = new Redis($logger, 'redis_host','redis_user','redis_pass'); $acme = new Acme($db,$redis, ...other_stuf...);
这有时被称为穷人的依赖性注射
你想要的东西(我猜)应该是这样的:
$coolContainer = new SomeCoolDependencyInjectionContainer();
// ... do some configuration on the container
$app = $coolContainer->get('app'); // or whatever its usage interface is
$app->run(); // or any other way to launch the app
容器知道如何构建应用程序及其所有组件(知识来自您为容器提供的配置或它的自动装配功能)。请注意,实例化在应用程序之外发生。应用程序应该已经构建了所有内容。
所以底线是:如果你正在使用一些DI容器,请确保它知道每个需要一个组件的记录器(实际上你可能想为应用程序的不同部分做特定的记录器)。 / p>
您可能会发现以下链接很有趣(当然,如果还没有阅读):
https://martinfowler.com/articles/injection.html
http://blog.ploeh.dk/2011/07/28/CompositionRoot/
依赖性更新:
通常在决定依赖数量时,请记住:
在我的实践中,它出现了,即使这些想法有点普遍,并且通用跟随它们使我的代码更清洁。清洁 - 一方面更具可读性和可理解性,另一方面更易于维护,更重要的是,因为它可以更快地执行重构或重新设计,而且工作量更少。所以基本上我认为这里的最佳实践不是特定于问题,而是反映了更高层次的普遍性。
尽管如此,关于一个班级的最终依赖数量,我不会遵循3的规则,无论什么"基础。偶尔我甚至可以有四个。通常,如果辅助类内部没有真正的逻辑,就会发生这种情况。嗯,它肯定有逻辑,但不是 那种逻辑。所以一般来说,如果我认为它不值得努力,我会让它留下来,直到出现一些真正的问题或者只是永远。