控制反转(依赖反转)系统中的事件是以哪种方式进行的?
向上还是向下 ?
我是一个非常视觉的人。 我在想我的应用程序是一个层次结构,顶层是根,底层是叶。
我还了解到IoC容器不知道它们包含的对象的责任/功能。 相反,包含的对象通过一些抽象接口了解它们的容器,即“上下文”。
UP:(非IoC方式?)我的事件是否应该从我的层次结构的底部发出,并通过责任链模式向上冒泡到父母,以便包含的对象不知道它们的容器? 例如,我的GUI中的一个按钮会分派一个CLICKED事件,该事件由通过关闭自身进行响应的侦听容器窗口捕获 。
DOWN: (IoC方式?)我的事件是否应该从容器的顶层调度到容器的顶部,并到达包含已直接订阅容器的侦听器,以便容器不知道其内容? 例如,一个容器窗口发送一个CLOSED事件,该事件由包含的按钮对象直接接收 ,该对象通过关闭自身进行响应,然后该窗口通过关闭自身来适应。
'Up'对我来说似乎很自然,但是由于IoC有一个容器不知道其包含的对象的行为,我不想回应他们的事件。
我意识到几乎任何系统的任何部分都可以监听事件,但我想了解IoC参与者之间的基本关系, 所以我可以正确构建它们 。 我假设人们通常不会分散关于他们程序的事件,而不考虑结构关系,依赖关系等。
我的问题来自IoC系统中的职责安排 - 包含对象的责任是对容器进行调用,并且容器负责为其依赖对象提供服务(这颠倒了非IoC范式 - 因此是同义词“依赖关系反转“)。 这似乎是IoC的一个非常重要的基本组成部分 - 职责转移。 我认为调用一个对象的函数或者监听它的事件都是依赖于另一个对象的例子。 当一个对象基于另一个对象定义自己的行为时,我称之为依赖关系,因为一个对象知道另一个对象,并且知道另一个对象所做的事情。 它在另一个对象的上下文中定义了自己。 据我所知,IoC被设置为使得包含的对象依赖于容器,所以它应该是被包含的对象有责任知道所有关于容器的信息。 而且它不应该是容器有责任知道所包含的对象。 因此,对于CONTAINER来说,监听CONTAINED注入对象上的事件在我看来就像是错误的责任,因为这意味着它知道关于它的内容。
在学习依赖“注入”和“反转”后,这个问题已经被重新表达了。 上一个问题在这里找到
为了简洁起见,我将引用容器中包含的对象作为“客户端对象”或“客户端”......
事件可以合法地在两个方向上流动,而不会在容器和客户端之间引入不需要的依赖关系。 实际上,允许容器从客户端接收事件是减少这些依赖关系的好方法。 它们为松耦合提供了一条准确的路径,以便容器能够在与客户进行通信的同时仍然不知道客户实际在做什么。 只要事件是由容器定义的,而不是由客户定义的。
你似乎主要关心的是客户端对象会触发容器使用的事件。 如果这些事件是由客户端对象定义的,这将是一个问题。 这显然会从容器中创建对客户端对象的严格依赖关系; 容器必须知道那些客户定义的事件并且专门为他们编码。 这将打败IoC的主要想法。 但是,如果这些事件是由容器定义的,那么这不是问题 - 事实上,这是保持容器与客户端对象松散耦合的最佳方式。 客户可以启动这些事件供容器消费,但他们没有定义这些事件。 它们只能触发容器根据容器定义的知道如何侦听的一组事件。 (当然,他们可以将其他事件用于其他目的,但容器不会知道或关心)。
例如,考虑一下容器提供了显示和打印“视图”的能力,这些视图是UI中的小内容框(这似乎是自从你提到过很多GUI示例以来,在你的文章中暗示的那种环境 - 但这些概念适用于任何与GUI无关的事情)。 该容器公开了一个名为Print的事件,该事件取得了关于要打印什么的一些参数(可能是对IPrintable界面的引用,可能要打印的原始数据取决于您试图用IoC实现的内容)。 在用户按下客户端对象上的某个按钮时,在容器内部运行的客户端对象可以触发Print事件。 然后容器将接收该事件并代表客户端对象处理打印。 或者客户端对象可以触发容器将接收的“CloseMe”事件,并且作为响应,将销毁触发事件的客户端对象(以及其他处理,包括可能询问用户是否确定等)
相反,容器可以在客户端对象感兴趣的事情发生时触发事件。同样,这些都只在容器中定义。 但客户端对象可能会订阅它们。 从前面的示例中,容器可能会公开客户端对象可能使用的PrintFinished事件,以便在用户界面中向用户显示一条消息,说明“您的文档已完成!” 该容器可以触发一个ApplicationClosing消息,在该容器完全关闭之前,所有客户端对象都可以使用该消息来拆除它们所持有的本地资源。 这些只是愚蠢的,简单的例子,但希望他们展示这个想法。
总而言之,我认为这不仅是合法的,而且对于从集装箱到客户以及从客户到集装箱两个方向的事件都非常有用。 与“上”或“下”无关的关键在于谁定义了这些事件。 容器定义了它们全部。
容器不应该有他们的组件知识或他们的行为。 容器的职责通常是实例化依赖的领域 - 而不是通信依赖。 一个容器应该是一个广义的工厂。
这就是结构图!=通信图的原因。 我相信你已经意识到,作为一个工厂,一个容器是你的对象图的根,但是一个响应或者发布一个事件的容器根本没有意义。
那么你想要的是一个管理事件的人。 一个知道事件的专门组件,可以将一个实例中介给感兴趣的各方。 你想要一个广义的事件代理。 一个事件路由器,如果你愿意。
你可能会找到很多的实现。 比如Cab的EventBroker,Prism的事件聚合器,或者我最喜欢的EventHub。 最后一个是与Cab广泛合作以及与肯特的杰里米米勒和格伦布洛克的对话,这是一位非常酷的人。
如果您正在使用容器,则可能熟悉依赖注入和控制反转。 需要发布事件的人被注入IEventHub并使用强类型主题类调用发布。 需要订阅事件的人也会注入一个IEventHub,并实现一个强类型的ISubscriber接口[基本上公开强类型的接收方法]。 而已。
现在,事件可以按照业务要求允许的任何方式进行,正如他们应该那样。
链接地址: http://www.djcxy.com/p/82233.html上一篇: Events in an Inversion of Control (Dependency Inversion) system go which way?