这是不是有太多依赖项无法通过构造函数注入到对象中?
Posted
技术标签:
【中文标题】这是不是有太多依赖项无法通过构造函数注入到对象中?【英文标题】:Is this too many dependencies to inject into an object through the constructor?这是否有太多依赖项无法通过构造函数注入到对象中? 【发布时间】:2011-06-11 08:34:22 【问题描述】:我正在使用 OO php 开发一个社交网络类型的项目,我不想使用现有的框架。做这个项目的主要目的是帮助我了解更多的东西。
这个问题更多的是关于依赖注入。
假设我有这些课程:
核心类 - 一些在应用程序中执行操作的核心方法配置类 - 加载站点配置内容数据库类 - 连接到 mysql 并执行所有与数据库相关的工作记录器类 - 用于记录错误和调试信息验证码类 - 用于表单上的验证码会话类 - 启动会话开始并添加、删除、获取要在应用中使用的会话变量缓存类 - 类似于会话类,但用于缓存项目(文件缓存、memcache、apc 缓存。我什至可以将我的会话内容添加到此类中,因为所有这些缓存都可以使用相同类型的方法)
上述所有类很可能会在我的应用程序的每个页面加载时使用(我可能错过了稍后将添加的更多类)
现在除了需要注入到大多数其他类中的上述类之外,我还有更多的类。我将有一个称为模块的部分,其中包含...
帐户类 - 创建新用户、验证用户身份、让用户进出应用、更新用户设置等等。用户类 -显示用户个人资料、在线显示用户、新用户以及所有向网站用户显示的内容论坛类 - 将用于论坛部分博客类 - 用于博客部分照片类 - 所有照片相关的东西cmets 类 - 处理照片和个人资料的 cmets
对于网站的不同部分,将会有更多此类类型的课程。 上面列出的第二组类很可能需要将第一组中的大多数类注入其中。
那么我是否应该使用注册表来存储第一组类中的对象并将注册表注入到第二组类中的所有类对象中?
或者我应该使用构造函数来加载它们吗?在此示例中,将有 7 个对象注入到其他类中,这似乎很多。我要解决这个问题了吗?
---编辑--- 我知道单例模式,但我认为这不是我最好的选择
---编辑 2--- 正如一些人所提到的,需要传递多达 7 个对象确实看起来很多,这就是我寻找建议的原因。对我来说幸运的是,这个项目还处于起步阶段,所以现在是改变结构的时候了。
我的论坛部分中的课程就是一个例子。论坛类需要访问会话数据、可能的缓存数据、配置对象、数据库对象。我是不是走错路了?
【问题讨论】:
相关:***.com/questions/2420193/… 删除了我的回复,因为你也提到了。使用注册表模式。 如果您的对象需要注入 7 个对象才能正常工作,我会挑战这些类本身的底层架构。理想情况下,您应该只需要几个对象。或者,依赖注入容器可以减轻你的一些压力..就我个人而言,我不是粉丝。 @CaseySoftware 这也是我的想法,但我不确定 你有没有想过使用 Context 来传递对象,比如new Context($db,$logger,$session,$filter)
,然后做new Account($Context)
?
【参考方案1】:
或者我应该使用构造函数来加载它们吗?在此示例中,将有 7 个对象注入到其他类中,这似乎很多。我是不是搞错了?
当您开始需要注入那么多对象时,您需要询问接收它们的对象是否负责太多。可以分解成小块吗?
如果实在不行,那就考虑把相关对象封装在另一个类中。也许您的会话、记录器和配置对象可以注入到App
或Application
对象中?
编辑:到目前为止,我注意到大多数其他答案都在谈论单例。请注意,单身人士是 DI 的敌人。在 here 上进行精彩的 Google 技术讲座。
编辑 2:
我所说的封装是指,与其将Session
、Logger
、Config
等全部注入到您的Account
类中,不如将它们注入到Application
类和@ 987654330@实例可以注入Account
。
老实说,这仍然是一个我正在绕圈子的 DI,但我开始看到的是:你应该只将它直接需要操作的对象注入到 Account
中。这些对象可能还需要操作其他对象,但Account
不需要知道。
通常,您会发现您甚至不需要像您想象的那样多的“层”。如果你发现你在到处注入东西,考虑各种重组你的应用程序的方法。让我从模型的 Pylons 文档中提取一段代码:
a = model.Person()
a.name = "Aaa"
a.email = "aaa@example.com"
meta.Session.add(a)
(不用担心meta.Session
...基本上它处理与数据库的交互。)
在这里,我们实例化一个Person
,设置它的几个属性,然后保存它。您会注意到Person
类对数据库一无所知,实际上甚至没有save()
方法。相反,我们将它传递给保存它的数据库类 (meta.Session
)。我们已经从数据库代码中分离出对Person
逻辑的关注。 meta.Session
可以以十几种不同的方式工作,但只要它知道如何阅读 Person
,我们就可以了。 (在这种情况下,在应用程序初始化期间,它会读取所有应用程序模型的定义)。
好的,我来总结一下,因为我显然在这里闲逛了很多。您的问题没有一个“正确”的答案(据我所知,但我绝不会宣称自己是 DI 专家)。
是的,注入多个对象可能表明需要进行重组,但您需要考虑许多因素:
是不是接收注入的对象责任太大了;可以分离出来吗? 您是否只注入接收者类直接需要使用的对象? 您是否注入了错误的方向;可以将您的Account
对象注入您的 Database
而不是相反吗?
【讨论】:
我在我的 OP 中添加了一点,但是你说的“将相关对象封装在另一个类中”是什么意思 +1 依赖注入的优点是可以从其他地方提供像 Logger 这样的 Account 类不应该知道如何创建的东西。如果可以在 Application 类的一些可配置和环境感知初始化期间实例化其中的许多东西,那么注入 Application 会给你一个漂亮整洁的包。当您添加一个新的、广泛使用的类时,您不必更改项目中的每个构造函数。 如果我们谈论的是 GOF 单例,我自己并不喜欢单例。然而,拥有某些对象的单个实例本身并不是一种反模式。事实上,许多 DI 容器允许将实例注册为(非 GOF)单例。我还认为 Session、Logger 和 Config 是横切关注点,可能不是 DI 的最佳候选者。 (除此之外,为您的回答 +1 :)。 @phil-sandler:完全同意。只实例化一个类的一个实例并没有错。只是类本身并没有强制执行它。 “跨领域”是什么意思? 更多深思:blog.ploeh.dk/2010/02/02/RefactoringToAggregateServices.aspx【参考方案2】:我一直更喜欢注册表方法。
原因:
范围更大 很容易获得 构造函数不再需要将对象作为变量(允许更好的使用) 允许您在类中使用更多对象,以便在需要时随意获取所需内容。虽然您可以尝试另一种方法,那就是使用单例模式,您可以在每个类中都有一个方法来跟踪自己的对象。
例如,创建一个这样的接口:
interface ISingleton
public static getInstnace();
然后,您可以为每个对象添加用于获取实例的方法。
class SomeObject implements ISingleton, ISomeThingElse
private static $_instance;
public static getInstance()
if(self::$_instance === null)
self::$_instance = new SomeObject();
return self::$_instance;
这样您始终保持对象的相同实例以及具有全局范围。
例子:
public function GetUser($id)
return Database::getInstance()->fetchUserById($id);
希望这会有所帮助。
还有另一种方法,那就是创建一个上下文类,让我试着解释一下:
该类的作用类似于一个注册表,但是是一次性的,例如:
class Context
private $objects = array();
public function Add($key,$Object)
$this->objects[$key] = $object;
public function __get($key)
return isset($this->objects[$key]) ? $this->objects[$key] : null;
并使用它作为容器来保存您的对象,如下所示:
$Context = new Context();
$Context->Add("database",$database);
$Context->Add("logger",$logger);
$Context->Add("session",$session);
$UserObject = new RegularUser($Context);
这样您可以对一组对象进行分组并将相同的上下文传递给其他几个库对象。
【讨论】:
-1 这是依赖注入的对立面,是一个可怕的设计决策。 请发布一个答案来解释您的建议。 我过去使用过这样的代码,但我希望改进我的代码,所以我正在寻找其他替代方案 那很好,我想我会为你添加一个技巧。 另外,我很想看到@cdhowie 的实施,因为他听起来对此事有更好的看法:) .. 知识就是力量!以上是关于这是不是有太多依赖项无法通过构造函数注入到对象中?的主要内容,如果未能解决你的问题,请参考以下文章