Multilevel Event Processing Model

An event in object-oriented programming (OOP) is a message that occurs at various points in the executable code when certain conditions are met. These messages are sent to processors (listeners), which allows you to respond in a timely manner to the changed state of the system.

Event-oriented programming is very popular. This programming paradigm says that program execution is determined by events - user actions (keyboard, mouse), messages from other programs and threads, operating system events, etc.
The advantages and applications of the event model are extremely wide:
  • when binding objects by events, objects do not need to “know” about each other;
  • this mechanism clearly fits into the concept of OOP;
  • this mechanism makes it easy to implement user interfaces, where each user action is an event, it is enough to “hook” handlers on these events;
  • when implementing server applications, the event model allows you to get rid of the generation of many serving processes;
  • The event model is also often used when programming games in which many objects are controlled.

There are design patterns that are somehow related to event handling: Observer, Team, Responsibility Chain, and many others. These patterns are used in many event processing models. However, various implementations of the event model impose a number of restrictions on the possibility of developing programs:
  • when processing an event, you cannot select the main handler; all handlers are equal to each other;
  • when processing an event, the handlers do not know anything about each other and about the current situation, which does not allow the programmer to fully implement the intended functionality;
  • you have to add additional functionality if you want to select the resulting handler.

The list of these restrictions is not complete, however, these restrictions are the most significant. This article proposes the implementation of a more complex event model, which will remove all of these restrictions.
When developing software using this event processing model, the sequence of processing steps is as follows:
  1. Necessary listeners are connected to process their events.
  2. In program code, an event is triggered.
  3. The “first round” of processing is performed, all listeners who are connected to the processing of this event are given time for primary processing, during which each listener can receive their own data, data from the initiator of the event, as well as set any data for transmission to the “second round” and apply for event processing in the "second round".
  4. Among all the listeners of this event, the listener who chooses the application with the highest processing priority is selected, it is he who is granted the right to process the event in the "second round". In the process of this processing, he can receive data from the initiator, his own data, data from his own handler of the "first round". After processing is complete, it can return data directly to the event initiator.

Consider the advantages of this model:
  • It is possible to “hang” the same handler on different events or even on the same thing, but with different own data.
  • It is possible to handle the widest range of events. For example, adding a new user, displaying the design of a website page, etc. In this case, the event of adding a new user can be processed using only the "first circle", and the event of the output of the site page design must be processed in "two circles".
  • Only one “second circle” handler is executed (Consider the site design output event: on the first circle, analyzing the state of the system, the processors prioritize the processing of the event, and only on the “second circle” one of them generates the site page design).

The picture shows the implementation scheme of this model. This implementation initially relies on work using a call chain. The following is an example implementation of a model in PHP.
  • Events is the main class. Only its object can the user create. This class provides the ability to trigger events and “hook” event handlers.
    • newListener - allows you to add a new listener and immediately "configure" it (adding occurs through the adapter for Events_Listener - Events_Listener_adapterSET).
    • newEvent - allows you to configure a new event and then trigger it (this action occurs through the adapter for Events_Fire - Events_Fire_adapterSET).

    Other classes are transparently connected to the user process:
    • Events_Fire - provides a common interface for working with an event, which is limited by adapters;
    • Events_Fire1 - when the first round of processing is called. This class allows you to get all available data of the current state, add a second circle handler, and also set its priority (via the Events_Fire2_adapterSET adapter);
    • Events_Fire2 - when calling the resulting handler ("second round"). This class allows you to get all available data, including data from the “first round” handler;
    • Events_Listener - provides a common interface for working with the event handler. Methods of this class also use adapters Events_Fire1, Events_Fire2;
    • Events_Data - a class for storing and transmitting data inside the event model.

Consider an example of the operation of this model:
class SampleListener
	public function Fire1(Event_fire1 $EF1)
		$EF1->setFinal(Array($this,”Fire2”), $EF1->getListenerData()->sort);
	public function Fire2(Event_fire2 $EF2)
		return ($EF2->getListenerData()->sort() + $EF2->getFireData()->sort());
$listener = new SampleListener();
$data1 = new Events_Data();
$data1->sort = 10;
Events::newListener("sampleModul", "sampleEvent", Array($listener, 'Fire1'))->setData($data1);
$data2 = new Events_Data();
$data2->sort = 20;
Events::newListener("sampleModul", "sampleEvent", Array($listener, 'Fire1'))->setData($data2);
$data3 = new Events_Data();
$data3->sort = 30;
Echo Events::newEvent("sampleModul", "sampleEvent")->setData($data3)->fire();

After the sampleEvent event is triggered, the Fire1 method of the $ listener is called with the first data (sort = 10, it will put this priority on the final processing) , and then the same method is called with other data (sort = 20, 20> 10, therefore the listener with this data will receive the right to final processing of the event) . In conclusion, the Fire2 method is called (the Handler is the same, but the data is $ data2) . The data from the event (sort = 30) is added to the data from the listener (sort = 20) . As a result, the event in return will return the number 50, which will be displayed on the screen.

This example shows that the same handler can respond differently to an event depending on the data of the listener. It also demonstrates the process of event processing, including the resultant, single call to Fire2 (Imagine that it is in this method, for example, that the page design of the site is generated, and the data is the external context of the event processing) .

By implementing this event processing model, it was possible to remove all the above limitations. Currently, the model is focused on a specific product (there are parasitic methods necessary only in this product), but if there is interest, then you can prepare the code for the public version.

You can also implement this model in other programming languages. In cpp, you can pass a pointer as data, and use reinterpret_cast in the processing methods or use templates.

The implementation in each specific situation may differ slightly, but the main point is precisely in the implementation of two or more levels.

Also popular now: