Table-driven method for data-driven programming the sample code in this article is in C language.
Previously introduced data-driven programming
talking about: What is the detailed explanation of data drive programming》。 It introduces a simple data-driven approach. Today, to introduce a slightly more complex, more practical bit of manipulation-table-driven method.
With regard to table drivers, it is mentioned in the UNIX programming art that a more detailed description can be seen in the Code encyclopedia, with a chapter devoted to the description (probably the eighth chapter).
Simple table-driven:
《
talking about: What is the detailed explanation of data drive programmingThere is a code example. It can also be viewed as a table-driven technique, except that the table is relatively simple, and it determines what functions are invoked using the call based on the message type after receiving the message.
a more complex table driver:
Considering a message (event) driven system, a module of the system needs to communicate with several other modules. When it receives a message, it needs to be handled differently according to the sender of the message, the type of message, and the state of itself. A more common approach is to use the three Cascade switch branch implementations for hard coding:
Copy Code code as follows:
Switch (Sendmode)
{
Case
}
Switch (msgevent)
{
Case
}
Switch (mystatus)
{
Case
}
disadvantages of this approach:
1, the readability is not high: Find a message processing part of the code needs to jump multilayer code.
2, too many switch branches, which is actually a duplicate code. They all have the same characteristics and can be refined further.
3, scalability is poor: If the program to add a new module state, this may change all the message processing functions, very inconvenient, and the process error prone.
4, the procedure lacks the backbone: lacks one to be able to sketchy the backbone, the program skeleton is submerged in the massive code logic.
Use the table-driven method to achieve:
Define a function jump table by defining three enumerations: module type, message type, Self module state:
Copy Code code as follows:
typedef struct __EVENT_DRIVE
{
Mode_type mod;//Message Sending module
Event_type event;//Message Type
Status_type status;//Self State
Event_fun eventfun;//processing function pointers in this state
}event_drive;
Event_drive eventdriver[] =//This is the definition of a table, not necessarily a table in a database. You can also make an array of the structures you define yourself.
{
{mode_a, event_a, Status_1, fun1}
{mode_a, event_a, status_2, fun2}
{mode_a, event_a, Status_3, fun3}
{mode_a, Event_b, Status_1, Fun4}
{mode_a, Event_b, status_2, fun5}
{mode_b, event_a, Status_1, fun6}
{mode_b, event_a, status_2, fun7}
{mode_b, event_a, Status_3, FUN8}
{mode_b, Event_b, Status_1, fun9}
{mode_b, Event_b, status_2, fun10}
};
int driversize = sizeof (eventdriver)/sizeof (event_drive)//Driver table size
Event_fun getfunfromdriver (mode_type mod, Event_type EVENT, Status_type STATUS)//Driver Table Lookup function
{
int i = 0;
for (i = 0; i < driversize i + +)
{
if ((eventdriver[i].mod = MoD) && (eventdriver[i].event = = event) && (Eventdriver[i].status = = status))
{
return eventdriver[i].eventfun;
}
}
return NULL;
}
The benefits of this approach are:
1, improve the readability of the program. How to handle a message, just look at the driver table to know, very obvious.
2, reduce the duplication of code. This method is certainly less code than the first. Why? Because it abstracts something that is repetitive: switch branching processing, the public stuff--based on the three element lookup processing method, is abstracted into a function getfunfromdriver plus a driver table.
3, scalability. Note that the function pointer, his definition is actually a contract, similar to the Java interface, C + + pure virtual functions, only meet this condition (in the parameter, return value), can be used as an event handler function. This has a little bit of a plug-in structure, you can easily replace these plug-ins, add, delete, and thus change the behavior of the program. And this change, the lookup of the event handler is isolated (or it can be called isolating the change). 、
4, the program has an obvious backbone.
5, reduce the complexity. The goal of controlling complexity is achieved by transferring the complexity of the program logic to the data that is easier to be processed by humans.
Inheritance and composition
Consider an event-driven module that manages many users, and each user needs to handle a lot of events. Then, we build the driver table is not for the module, but for the user, should be the user in a certain state, receive a module of the processing of an event. Let's assume that users can be divided into different levels, and that each level does not have the same treatment as mentioned above.
With object-oriented thinking, we can consider designing a user base class to achieve the same event processing method, according to different levels, define several different subclasses, inherit the public processing, and then implement different processing respectively. This is the most common kind of thinking, which can be called the Inheritance law.
What if the table-driven method is implemented? Directly design a user's class, no subclasses, and no specific event handling methods. It has a member, is a driver table, it received the event, all delegated to the driver table to handle. Depending on the level of the user, you can define several different driver tables to assemble different object instances. This can be called his combination method.
Inheritance and composition are also mentioned in the design pattern. The advantage of the combination is its scalability, elasticity, and encapsulation.
As for the driver table in this case, you can continue to use the structure, or you can use the object.
The above method of one point performance optimization recommendations:
If the performance requirements are not high enough, the above method can handle. If performance requirements are high, appropriate optimizations can be made. For example, you can create a multidimensional array, each of which represents a module, a state, a message. This allows you to navigate directly to the processing function based on the enumeration of these three, rather than look-up the table. (In fact, the data-driven idea: The structure is a static algorithm.) )
The more advanced, more abstract, data-driven programming should be the process script or DSL. I have written a simple parasitic XML script to describe the process. This piece of the back is a time introduction.