可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Up or down?
I'm a very visual person. I'm thinking of my application as a hierarchy, where the top is the root and the bottom is a leaf.
I'm also under the understanding that, in DI systems, containers are ignorant of their contained objects' responsibilities/functions. Instead, the contained objects know about their context because the context (a dependency) is injected in.
UP: (The non-DI way?)
Should my events be dispatched from the bottom of my hierarchy and bubble upwards to their parents? E.g. a button in my GUI dispatches a CLICKED
event, which is caught by a listening container that responds by carrying out the appropriate action.
DOWN: (The DI way?)
Should my events be dispatched from the top of my hierarchy by a parent that its children listen to? E.g. --... ok, i'm having trouble coming up with this. I'm thinking along the lines of a Mediator that dispatches events for contained objects.
'Up' seems natural to me, but since DI has a container being unaware of its contained objects' behavior, I wouldn't want to respond to their events.
EDIT (to clarify):
I realize it's POSSIBLE to have nearly any part of a system listen to an event, but I want to understand the fundamental relationship between DI participants, so I can structure them properly. I'm assuming people don't usually just scatter events about their program without regard to structural relationships, dependencies, etc.
My question arises from the responsibility placement in a DI system -- it's the injected object's responsibility to make calls on the injector and the injector's reponsibility to provide services to its dependent objects (which inverts the non-DI paradigm -- hence synonyms like "Inversion of Control" and "Dependency Inversion"). This seems to be a very important, fundamental component of DI -- a shifting of responsibilities. I consider calling an object's functions or listening to its events to BOTH be examples of depending on another object. When an object defines its own behavior based on another object, I call that a dependency because one object KNOWS of the other and also KNOWS what the other does. It has defined itself within the context of the other object. As I understand, DI is set up so that the injected object is dependent on the injector, so it should be the injected object's responsiblity to know all about the injector. And it should NOT be the injector's responsiblity to know about the injected object. So, for the injector to be listening to events on the CONTAINED injected object seems to me like like a misplacement of responsibilities because that means it knows something about its contents.
Please tell me if and how this is wrong.
回答1:
Dependency Injection and the role assignments within the Observer Pattern are orthogonal concerns. An object may play the role of the observer or observed and simultaneously be either the composing object, the composed object, both, or neither.
Consider a typical example where a button is composed by a control. When the button is clicked, it raises a Clicked event which is responded to by the containing control. In this case the observing object is composing the observed object.
Now consider a screen which composes a number of controls. The screen may raise a Closing event which allows the composed controls to perform their own cleanup work before the entire screen is closed. In this case, the observed object is composing the observers.
Now consider a screen which composes a button and a label. When the button is clicked, the label's Clear() method is called. In this case, neither observer nor observed composes the other, but both are composed by the screen object.
Now consider a screen which raises a Closing event which it itself subscribes to (perhaps ensuring itself to be the final event handler that is registered). When it raises a Closing event, allowing any observers to first perform any actions they might need, it then handles its own event. In this case, the observer is the observed.
Dependency injection concerns how an object obtains its dependencies. The dependency injected into a given object may contain an event the object wants to subscribe to, or the dependency may subscribe to the object it is being injected to. How two objects interact after one is injected into another doesn't really have anything to do with dependency injection.
EDIT
Concerning your clarification section, I believe I understand the source of your confusion. Traditionally, an object creates its own dependencies. Dependency injection inverts the responsibility of obtaining these dependencies by moving the knowledge of how the dependency is obtained outside of the object. Dependency injection doesn't invert dependency relationships however. You may be confusing Dependency Injection with the Dependency Inversion Principle. The Dependency Inversion Principle does reverse the dependency relationship between "high-level" and "low-level" objects, but dependency injection is only concerned with how dependencies are supplied to a given object. Therefore, use of dependency injection doesn't change how objects normally interact with one another. If prior to using dependency injection object B subscribed to events raised by object A (or vice versa), introducing dependency injection will not change this.
回答2:
In my experience events will start at the lower level and go up, so, your tire hits a pothole, which will vibrate the car, when the tire was injected into the car class.
But, you need to make certain that each part is able to handle the events.
If the car goes faster, the tire will spin faster, but that is not due to an event, but due to calling a function on the tire to have it achieve a certain speed.
I am seeing it as going up, but you didn't specify how you are determining the direction.
回答3:
I say bottom up is the way to go. What you're probably after is a chain of responsibility sort of pattern. Events start at the "leaves". The leaf either handles it, or passes it up the hierarchy to the parent object. The leaf's parent object either handles it or passes it further up the hierarchy, etc.
I don't think it violates any DI principles. All the objects in the hierarchy will have to implement an interface similar to this, though:
interface IEventHandler {
void setNextHandler(IEventHandler nextHandler);
void handleEvent(Event e);
}
回答4:
Using the Observer Pattern as the template, where the "parent" is the object dispatching the event and the "children" are the registered listeners waiting/observing the event and then acting on the event. So whether top-down, left-right, however you conceptualize it the principle remains the same.
EDIT: Look at this visual description for Observer
回答5:
Do you know something about message bus architecture, e.g. events and requests?
In Highly-concurrent systems, low layers are processing things such as I/O or mouse click etc which are time-comsumable or the operations might be blocked, e.g. disk I/O or network message Tx/Rx; while high layers are always processing faster operations, aka, logic computing because the high layers will not be involved into any I/Os etc.
In such a system, an Event is a notification that it notifies the high layers that something had happened. For example, the a packet had arrived, or a string had been written to the disk. Once the high layers get the notification, they will move on to fetch the data from the Event's buffer and parse the packet which was sent by the Event. As mentioned fetching and parsing are pure logic computing and very fast. After done, they may send a Request (e.g. send an ACK packet) to low layers. Requests from up to down are non-block, very fast too. Low layers will process the Requests and do "real sending", aka, I/O operations.
The high layers and low layers use queue facilities etc to make communication.
So in such systems, you'll agree that events should go upward from the bottom.
Up or down, it's up to the Model you had chosen.
See also for Highly-concurrent Model described in the ducoment "EffoNetMsg.pdf" at http://code.google.com/p/effonetmsg/downloads/list.
回答6:
How about passing event in a similar way to WPF binding?