In the previous blog, we analyzed the state mode. The state mode eliminates a large conditional branch, which transfers the object state to sub-classes, reducing mutual dependencies, this makes software maintenance simple and easier to expand later. This function seems to be similar to the responsibility chain model we are talking about today. The responsibility chain model focuses on class behaviors, and each class has its own request scope, when the client executes the request, it verifies the request according to the sequence specified in the chain until it finds a suitable request.
In terms of function implementation, the two have similarities, but their structures are essentially different. First, the responsibility chain model (chains and chains are very active and can be combined freely) the object in is not fixed. When using the client, we can specify the start and end ends of the chain at will. We can specify the intermediate execution process at will, which makes the request more flexible, however, the internal execution sequence of the Status mode is fixed, and the request method is fixed.
For a rough comparison of the two modes:
I. Theoretical Explanation
Responsibility Chain Mode: Enables multiple objects to process requests to avoid coupling between request senders and recipients. Connect the object to a chain and pass the request along the chain until an object processes it.
What is chain?
We can see that the chain has two important properties: ① is a collection of nodes; ② each node of the chain can be flexibly split and reorganized.
Usage
1. There are multiple objects to process the request. How can this problem be solved.
2. You want to submit a request to one of multiple objects without specifying the receiver explicitly.
3. The object set that can process a request should be dynamically specified.
The UML diagram is very simple. It mainly refers to the Inheritance and aggregation relationships. The following uses the "fight" as an example to implement chained requests.
In the army, the war requires the permission of the superiors. In actual situations, we divide the war situation into three levels, which are replaced by 1-10 numbers, and 1-4 is the first-level war report, assume that the commander can issue commands; 5-7 is a level-2 War Report; assume that the commander can issue commands; 8-10 is a level-3 war report; assume that the commander can issue War commands as appropriate; if the number is greater than 10, report to a higher level. The Code is as follows:
Handler processes the abstract request interface without specific request implementation. It is an abstract class of the teacher, military chief, and Commander, used to set the next successor of a specific request class.
Using system; using system. collections. generic; using system. LINQ; /// <summary> /// specifies the abstract interface for Request Handling. It is used to set the next successor. /// </Summary> abstract class handler {protected handler successor; /// <summary> /// abstract request method, override the implementation in the subclass /// </Summary> /// <Param name = "request"> </param> /// <returns> </returns> Public Abstract Boolean handlerequest (INT request ); /// <summary> /// set the successor /// </Summary> /// <Param name = "Successor"> successor </param> Public void setsuccessor (handler successor) {This. successor = successor;} // end Handler
Concretehandlera, a class teacher, judges the form, and issues War commands in the form of level-1. The form cannot report the control to the superior.
Using system; using system. collections. generic; using system. LINQ; /// <summary> /// class teacher's responsibility class /// </Summary> class concretehandlera: Handler {/// <summary> // The instructor executes the request, if the instructor executes the command, if the permission is exceeded, send an upstream request // </Summary> // <Param name = "request"> </param> // <returns> </returns> Public override Boolean handlerequest (INT request) {If (request <4 & request> 1) {console. writeline ("I am a teacher, do not fear them: {0}", request); // within the execution right of the teacher Then, execute the content} else if (successor! = NULL) {console. writeline ("I am a teacher and cannot execute the request, report to the superior: {0}", request); // if the teacher does not execute the power, execute the successor. handlerequest (request); // The instructor sends an upstream request} return true ;}// end concretestatea
Concretehandlerb, military chief class, judge the form again. If the form level is within the controllable range, execute the War Command. If the form level is beyond the control level, report it to the superior.
Using system; using system. collections. generic; using system. LINQ; /// <summary> /// duties class of the Military Chief /// </Summary> class concretehandlerb: Handler {// <summary> // The military chief executes the command, the command will be executed within the execution range of the Military Chief, if the permission is exceeded, send an upstream request // </Summary> // <Param name = "request"> </param> // <returns> </returns> Public override Boolean handlerequest (INT request) {If (request> 4 & request <7) {console. writeline ("I Am a military chief, do not fear them: {0}", request); // The request is sent to the Military Chief Within the scope of responsibility, the Chief Executive executes} else if (successor! = NULL) {console. writeline ("I Am a military chief, unable to execute the request, report to the superior: {0}", request); // The power is beyond the scope of the military chief, and the Military Chief cannot execute successor. handlerequest (request); // successor, the Military Chief continues to send up request} return true ;}// end concretestateb
Concretehandlerc, the Commander class, judges the form and determines whether to launch a large attack. If not, it will report to a higher level.
Using system; using system. collections. generic; using system. LINQ; /// <summary> /// commander's responsibility class // </Summary> class concretehandlerc: Handler {// <summary> // The Commander executes the request, if the command is executed by the commander, if the permission is exceeded, send an upstream request // </Summary> /// <Param name = "request"> execution greater than 20 and less than 30 </param> /// <returns> </returns> Public override Boolean handlerequest (INT request) {If (request> 7 & request <10) {console. writeline ("I'm the commander, do not fear them: {0}", re Quest); // The request is within the scope of the duties of the Commander. Execute the Commander} else {console. writeline ("I am the commander. To fight, please send a message from the Chairman of the Military Commission! "); // The power is beyond the range of the Military Chief, and the Military Chief cannot execute} return true ;}// end concretestatec
The facade class, that is, the client class, encapsulates the program entry. When using the responsibility chain, you can call the facade class to pass level parameters.
Using system; using system. collections. generic; using system. LINQ; using system. windows. forms; namespace system {static class facade {/// <summary> /// main entry point of the application. /// </Summary> [stathread] Static void main (string [] ARGs) {concretehandlera H1 = new concretehandlera (); // instantiate responsibility a object concretehandlerb H2 = new concretehandlerb (); // create responsibility B object concretehandlerc h3 = new concretehandlerc (); // create responsibility C object h1.setsuccessor (H2 ); // set the next successor B h2.setsuccessor (H3) for job A; // set the next successor C int [] requests = {2, 6, 9, 12} for Job B }; // pass the object to be requested // The loop execution request foreach (INT request in requests) {h1.han Dlerequest (request);} console. read () ;}}// program running result // I am a teacher, do not fear them: 2 // I am a teacher, cannot execute the request, report to the superior: 6 // I am the chief of the army, do not fear them: 6 // I am the chief of the army and cannot execute the request. Report to the superior: 9 // I am the chief of the army and cannot execute the request, report to the superior: 9 // I am the commander, do not fear them: 9 // I am the teacher and cannot execute the request. Report to the superior: 12 // I am the military chief, unable to execute the request, report to the superior: 12 // I am the commander and want to fight, the Chairman of the Military Commission must send a message!
After the above duty requests, the war behavior becomes very clear. This process of program execution is a typical chain mode (but the responsibility chain mode is not just a simple chain mode, it can have multiple branches ), the request sender and receiver do not have clear information from the other party, and the object in the chain itself does not know the structure of the chain. The result is that the responsibility chain simplifies the interconnectivity of objects. They only need to maintain a reference pointing to the successor, rather than the reference of all its candidates. At the same time, we can also add or modify the structure for processing a request at any time, which makes the software structure easier to expand and improves the system flexibility.
II. Application Instances
The following describes the application of the responsibility chain model by taking the students in the charging system go-and-go as an example.
Student computer business description: Students need to access the Internet in the school machine room, and they need to swipe their cards when surfing the Internet. For card swiping on the machine, we need to verify the information to determine whether the student's card number has been registered. Secondly, we need to determine the identity of online students in two situations: Temporary students and members access the internet, A temporary student has his/her own responsibility for accessing the Internet. The Member has a set of responsibilities for accessing the Internet. For members, the balance should be sufficient when they are on the computer. If the balance is insufficient, they should be prompted to recharge the account.
If we do not use the design mode to enable students to access the Internet, we need to chain the student information and select the computer. The code written in this way can be imagined as complicated. Complicated logic judgment, a long string of code, with poor maintainability and scalability. If we need to modify the computer service because of system upgrade, we will be crying.
What if we use the responsibility chain model? We divide the computer process into three specific categories of responsibilities: Student Information, balance, membership, and temporary users. After the division of duties, the class responsibilities are divided, not only in line with the design principles of the dimit Law, but also well in line with a single responsibility.
UML Structure Diagram for students to access the Internet:
Class sequence diagram
Describes the inter-call relationship between classes. The client first instantiates the specific responsibility class, then sets the chain's top and bottom, and finally executes the start request of the chain.
Login code implementation
Logstubll class, abstract responsibility class, defines the abstract interface for implementing machine operations, and sets the next successor for duties.
Imports entity. chargesystem. entityimports factory. chargesystem. factoryimports idal. chargesystem. idalnamespace chargesystem. bll ''' <summary> ''' student computer ''' </Summary> public class logstubll ''' <summary> ''' statement ''' </Summary> protected successor as logstubll ''' <summary> ''' sets the successor ''' </Summary> ''' <Param name = "successor1"> </param> Public sub setsuccessor (byval successor1 as logstubll) successor = successor1 end sub ''' <summary> ''' specific implementation class to be overwritten, student computer request ''' </Summary> ''' <Param name = "cardentity"> </param> Public overridable function handlerequest (byval cardentity as cardentity) as studententity return nothing end functionend class 'logstubllend namespace' BLL
Testcardinfobll class: Checks student information. After inputting the card number on the computer, the system checks the card number to verify whether the card number is on the computer. If the computer is on, an exception is thrown for the high-level module of the program to capture and process.
Imports entity. chargesystem. entityimports factory. chargesystem. factoryimports idal. chargesystem. idalnamespace chargesystem. bll ''' <summary> ''' checks the input card number. If no temporary user identity is used, ''' </Summary> public class testcardiinfobllinherits chargesystem. bll. logstubll dim dataaccess as dataaccess' defines the abstract factory, which is used to instantiate the return specific Dal class 'constructor, instantiate dataaccess sub new () dataaccess = new dataaccess end sub ''' <summary> ''' indicates the specific implementation class to be rewritten to determine whether the card number is being mounted. Host ''' </Summary> ''' <Param name = "cardentity"> </param> Public overrides function handlerequest (byval cardentity as cardentity) as studententity dim onlinedal as ionlineidal = dataaccess. createonline () 'defines the interface class on the machine and assigns dim tmpstudal as itempstuidal = dataaccess to the class. createtmpstu () 'defines the temporary host information table and assigns dim enonline as onlineentity = nothing' to it. defines the physical class dim enlinelog as linelogentity = nothing ', which defines the host recording object class '--- Comment 'generally, the user determines whether the card number is on the machine. enonline = onlinedal. selectbycid (cardentity) 'assigns a value to the card entity class' to determine whether the card number is on the machine. If it does not exist, an exception is thrown, determine whether a user is on the machine as a temporary user if not enonline is nothing then throw new exception ("this card number is on the machine! ") End if 'hangzhou' temporarily determines whether the card number is on the machine. enlinelog = tmpstudal. selectbycardpart (cardentity) 'assigns a value to the physical class on the machine.' If enlinelog is not empty, it is on the machine. An exception is thrown if not enlinelog is nothing then throw new exception ("this card number is on the machine! ") End if 'forward' jumps out of the next responsibility if not successor is nothing then successor. handlerequest (cardentity) 'requests the next responsibility end if return nothing end functionend class 'testcardiinfobllend namespace' BLL
Leastbalancebll, minimum balance. It is mainly responsible for querying the Member's card number balance and comparing it with the minimum amount restricted by the system to deal with students with insufficient balance, ensure that the student balance is sufficient for Internet access.
Imports entity. chargesystem. entityimports factory. chargesystem. factoryimports idal. chargesystem. idalnamespace chargesystem. bll ''' <summary> ''' minimum balance. If the balance is less than this, it indicates that the machine cannot be connected ''' </Summary> public class leastbalancebllinherits chargesystem. bll. logstubll dim dataaccess as dataaccess 'abstract factory 'instantiate Abstract Factory sub new () dataaccess = new dataaccess end sub ''' <summary> ''' specific implementation class ''' </Summary> ''' <Param name = "cardentity"> </PA Ram> Public overrides function handlerequest (byval cardentity as cardentity) as studententity dim ensetcahrge as setchargeentity 'defines the billing information and sets the entity class dim dalsetcharge as isetchargeidal = dataaccess. createsetcharge () 'instantiate the billing system. Set the Dal class dim dalcard as icardidal = dataaccess. createcard () 'defines the card table Dal class ensetcahrge = dalsetcharge. selectnew () 'get the latest billing amount cardentity = dalcard. selectbycid (cardentity) 'query and obtain the card number Information' to determine the user's Remainder Sufficient amount if cardentity. dblbalance <ensetcahrge. dblleastcash then throw new exception ("this student balance is insufficient" & ensetcahrge. dblleastcash & "RMB, please recharge your account and try again! ") End if 'is transferred to the next place, jump to the normal machine if not successor is nothing then' to the next place, and jump to the normal machine successor. handlerequest (cardentity) end if return nothing end functionend class 'leastbalancebllend namespace' BLL
Tmpstubll and temporary users can access the internet. Temporary users and members may access the Internet. This class is mainly used to judge the user's identity and ensure that the temporary user is on the machine.
Imports entity. chargesystem. entityimports factory. chargesystem. factoryimports idal. chargesystem. idalnamespace chargesystem. bll ''' <summary> ''' On-Demand user ''' </Summary> public class tmpstubllinherits chargesystem. bll. logstubll dim dataaccess as dataaccess' defines the abstract factory, which is used to instantiate the return specific Dal class 'constructor, instantiate dataaccess sub new () dataaccess = new dataaccess end sub ''' <summary> ''' specific implementation class ''' </Summary> ''' <Param name = "cardentity"> </param> Public overrides function handlerequest (byval cardentity as cardentity) as studententity dim encardentity as cardentity = nothing 'defines the card information entity class dim dalcard as icardidal = dataaccess. createcard defines the card Dal class without assigning dim daltempstu as itempstuidal = dataaccess. createtmpstu () 'defines the temporary user Dal class encardentity = dalcard. selectbycid (cardentity) 'assigns a value to the card entity class' to determine whether the card number is a registered card number. If not, the information on the temporary user will prevail if encardentity is nothing then daltempstu. insert (cardentity) 'To write information to else successor in the t_tempstudent table. handlerequest (cardentity) 'is transferred to the next end if return nothing 'Return the end functionend class 'tmpstubllend namespace' BLL
Normalstubll and members access the Internet. This class is responsible for implementing members' online requests. when requests are in the role of this class, this class of processing functions Ensure that system members can access the Internet normally.
Imports entity. chargesystem. entityimports factory. chargesystem. factoryimports idal. chargesystem. idalnamespace chargesystem. bll ''' <summary> ''' normal student users' computers ''' </Summary> public class normalstubllinherits chargesystem. bll. logstubll dim dataaccess as dataaccess' defines the abstract factory, which is used to instantiate the return specific Dal class 'constructor, instantiate dataaccess sub new () dataaccess = new dataaccess end sub ''' <summary>, write the machine information ''' </Summary> ''' <Param name = "cardentity"> </param> Public overrides function handlerequest (byval cardentity as cardentity) to the online table) as studententity dim dalonline as ionlineidal = dataaccess. createonline () 'defines the active table dalonline. insert (cardentity) 'insert student's return nothing 'return value end function end class 'normalstubllend namespace' BLL
Iii. Comparison of sublimation responsibility chain mode and decoration Mode
The UML diagram structure of the decoration mode is roughly the same as that of the responsibility chain mode. Similarly, the function of the decoration mode can also be implemented by the responsibility chain mode, but which of the following is more advantageous in implementation. The decoration mode belongs to the structural design mode, which tends to the layout and relationship between objects. It provides a function to dynamically add classes, effectively separating the core responsibilities of classes from the decorative functional area, removing repeated decorative logic in the relevant classes. It complies well with the open-closed principle, and also provides a better way to expand object behavior than inheritance, that is, combination. In terms of adding functions, the decoration mode is more flexible than the inherited Child class.
It mainly applies:
1. You need to expand the functions of a class or add additional responsibilities to a class;
2. You need to dynamically add functions to an object. These functions can be dynamically revoked;
3. A large number of functions need to be added by the arrangement and combination of some basic functions to make the inheritance relationship unrealistic.
4. When the subclass generation method cannot be used for expansion. One case is that there may be a large number of independent extensions. To support each combination, a large number of subclasses will be generated, resulting in explosive growth of the number of subclasses. Another scenario is that the class definition is hidden, or the class definition cannot be used to generate a subclass.
However, the responsibility chain model is a behavior design model that focuses on behavior. Its use can make the behavior of objects clearer and improve the efficiency of collaboration between objects.
As far as the Internet function is concerned, it focuses more on the behavior between classes and classes, and uses the responsibility chain mode just right. This improves the efficiency of implementing complex requests for students to access the Internet and makes the online behavior clearer. The decoration mode is not applicable here. If you use the decoration mode to dynamically Add the function on the basis of the original class, it not only simplifies the processing process, but also reduces the efficiency of students' online access.